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

SpringBoot+SpringSession+Redis实现session共享及唯一登录最近在学习 springboot session 这个点一直困扰了我好久 今天把这些天踩的坑分享出来吧 希望能帮助更多的人 一 pom xml 配置 dependency groupId org springframew boot groupId artifactId spring boot starter da artifactId dependency

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

一、pom.xml配置 

 
   
   
     org.springframework.boot 
    
   
     spring-boot-starter-data-redis 
    
   
   
   
     org.springframework.session 
    
   
     spring-session-data-redis 
    
  

二、application.properties的redis配置

#redis spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password= 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上登录的账号就失效了。

浏览器:

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

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

postman:

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

七、核心原理详解

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

1、redis:

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

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

同时还要保证配置正确

@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配置成功!

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

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状态。

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/229518.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月16日 下午4:32
下一篇 2026年3月16日 下午4:32


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号