SpringBoot+SpringSession+Redis实现session共享及唯一登录示例

 更新时间:2021年04月29日 16:45:18   作者:保尔-科查筋  
这篇文章主要介绍了SpringBoot+SpringSession+Redis实现session共享及唯一登录示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

最近在学习springboot,session这个点一直困扰了我好久,今天把这些天踩的坑分享出来吧,希望能帮助更多的人。

一、pom.xml配置 

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
 
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>

二、application.properties的redis配置

#redis
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=123456
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
#超时一定要大于0
spring.redis.timeout=3000
spring.session.store-type=redis

在配置redis时需要确保redis安装正确,并且配置notify-keyspace-events Egx,spring.redis.timeout设置为大于0,我当时这里配置为0时springboot时启不起来。

三、编写登录状态拦截器RedisSessionInterceptor

//拦截登录失效的请求
public class RedisSessionInterceptor implements HandlerInterceptor
{
    @Autowired
    private StringRedisTemplate redisTemplate;
 
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
    {
        //无论访问的地址是不是正确的,都进行登录验证,登录成功后的访问再进行分发,404的访问自然会进入到错误控制器中
        HttpSession session = request.getSession();
        if (session.getAttribute("loginUserId") != null)
        {
            try
            {
                //验证当前请求的session是否是已登录的session
                String loginSessionId = redisTemplate.opsForValue().get("loginUser:" + (long) session.getAttribute("loginUserId"));
                if (loginSessionId != null && loginSessionId.equals(session.getId()))
                {
                    return true;
                }
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
 
        response401(response);
        return false;
    }
 
    private void response401(HttpServletResponse response)
    {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
 
        try
        {
            response.getWriter().print(JSON.toJSONString(new ReturnData(StatusCode.NEED_LOGIN, "", "用户未登录!")));
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
    {
 
    }
 
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
    {
 
    }
}

四、配置拦截器

@Configuration
public class WebSecurityConfig extends WebMvcConfigurerAdapter
{
    @Bean
    public RedisSessionInterceptor getSessionInterceptor()
    {
        return new RedisSessionInterceptor();
    }
 
    @Override
    public void addInterceptors(InterceptorRegistry registry)
    {
        //所有已api开头的访问都要进入RedisSessionInterceptor拦截器进行登录验证,并排除login接口(全路径)。必须写成链式,分别设置的话会创建多个拦截器。
        //必须写成getSessionInterceptor(),否则SessionInterceptor中的@Autowired会无效
        registry.addInterceptor(getSessionInterceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/user/login");
        super.addInterceptors(registry);
    }
}

五、登录控制器

@RestController
@RequestMapping(value = "/api/user")
public class LoginController
{
    @Autowired
    private UserService userService;
 
    @Autowired
    private StringRedisTemplate redisTemplate;
 
    @RequestMapping("/login")
    public ReturnData login(HttpServletRequest request, String account, String password)
    {
        User user = userService.findUserByAccountAndPassword(account, password);
        if (user != null)
        {
            HttpSession session = request.getSession();
            session.setAttribute("loginUserId", user.getUserId());
            redisTemplate.opsForValue().set("loginUser:" + user.getUserId(), session.getId());
 
            return new ReturnData(StatusCode.REQUEST_SUCCESS, user, "登录成功!");
        }
        else
        {
            throw new MyException(StatusCode.ACCOUNT_OR_PASSWORD_ERROR, "账户名或密码错误!");
        }
    }
 
    @RequestMapping(value = "/getUserInfo")
    public ReturnData get(long userId)
    {
        User user = userService.findUserByUserId(userId);
        if (user != null)
        {
            return new ReturnData(StatusCode.REQUEST_SUCCESS, user, "查询成功!");
        }
        else
        {
            throw new MyException(StatusCode.USER_NOT_EXIST, "用户不存在!");
        }
    }
}

六、效果

我在浏览器上登录,然后获取用户信息,再在postman上登录相同的账号,浏览器再获取用户信息,就会提示401错误了,浏览器需要重新登录才能获取得到用户信息,同样,postman上登录的账号就失效了。

浏览器:

postman:

七、核心原理详解

分布式session需要解决两个难点:1、正确配置redis让springboot把session托管到redis服务器。2、唯一登录。

1、redis:

redis需要能正确启动到出现如下效果才证明redis正常配置并启动

同时还要保证配置正确

@EnableCaching
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 30)//session过期时间(秒)
@Configuration
public class RedisSessionConfig
{
    @Bean
    public static ConfigureRedisAction configureRedisAction()
    {
        //让springSession不再执行config命令
        return ConfigureRedisAction.NO_OP;
    }
}

springboot启动后能在redis上查到缓存的session才能说明整个redis+springboot配置成功!

2、唯一登录:

1、用户登录时,在redis中记录该userId对应的sessionId,并将userId保存到session中。

HttpSession session = request.getSession();
session.setAttribute("loginUserId", user.getUserId());
redisTemplate.opsForValue().set("loginUser:" + user.getUserId(), session.getId());

2、访问接口时,会在RedisSessionInterceptor拦截器中的preHandle()中捕获,然后根据该请求发起者的session中保存的userId去redis查当前已登录的sessionId,若查到的sessionId与访问者的sessionId相等,那么说明请求合法,放行。否则抛出401异常给全局异常捕获器去返回给客户端401状态。

唯一登录经过我的验证后满足需求,暂时没有出现问题,也希望大家能看看有没有问题,有的话给我点好的建议!

到此这篇关于SpringBoot+SpringSession+Redis实现session共享及唯一登录示例的文章就介绍到这了,更多相关SpringBoot 唯一登录内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring+SpringMVC配置事务管理无效原因及解决办法详解

    Spring+SpringMVC配置事务管理无效原因及解决办法详解

    这篇文章主要介绍了Spring+SpringMVC配置事务管理无效原因及解决办法详解,具有一定借鉴价值,需要的朋友可以参考下
    2017-12-12
  • mybatis中@Param注解总是报取不到参数问题及解决

    mybatis中@Param注解总是报取不到参数问题及解决

    这篇文章主要介绍了mybatis中@Param注解总是报取不到参数问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • Java简单实现对一串数字采用相应的加密策略后传输

    Java简单实现对一串数字采用相应的加密策略后传输

    下面小编就为大家带来一篇Java简单实现对一串数字采用相应的加密策略后传输。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • JAVA线程用法详解

    JAVA线程用法详解

    这篇文章主要介绍了JAVA线程用法,配合实例针对Java中线程的开启、sleep、合并与让出等进行了较为深入的分析,需要的朋友可以参考下
    2014-08-08
  • Java原生方法实现 AES 算法示例

    Java原生方法实现 AES 算法示例

    这篇文章主要介绍了Java原生方法实现 AES 算法,结合实例形式分析了Java实现AES加密算法的相关操作技巧,需要的朋友可以参考下
    2019-03-03
  • springBoot 插件工具热部署 Devtools的步骤详解

    springBoot 插件工具热部署 Devtools的步骤详解

    这篇文章主要介绍了springBoot 插件工具 热部署 Devtools,本文分步骤给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • Java数据结构之链表的增删查改详解

    Java数据结构之链表的增删查改详解

    在这篇文章中,小编将带大家了解一下Java数据结构中链表的增删查改(以下结果均在IDEA中编译)希望在方便自己复习的同时也能帮助到大家
    2022-09-09
  • Maven中央仓库地址配置大全

    Maven中央仓库地址配置大全

    这篇文章主要介绍了Maven中央仓库地址配置大全,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • spring security 自定义Provider 如何实现多种认证

    spring security 自定义Provider 如何实现多种认证

    这篇文章主要介绍了spring security 自定义Provider实现多种认证方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • IDEA 格式化SQL代码技巧分享

    IDEA 格式化SQL代码技巧分享

    这篇文章主要介绍了IDEA 格式化SQL代码技巧分享,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-02-02

最新评论