使用SpringSession + Redis 的方式实现分布式Session登录功能
1.导入依赖
1 2 3 4 5 6 7 8 9 10 11 12
| <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> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
|
2.配置Redis
1 2 3 4 5 6 7 8 9 10 11 12
| spring: redis: host: XX.XXX.XXX.XX port: 6379 password: 123456 database: 0 lettuce: pool: max-active: 10 max-idle: 10 min-idle: 1 time-between-eviction-runs: 10s
|
3.添加注解
在启动类上添加**@EnableRedisHttpSession**注解
4.验证码登录
此处使用近期的项目“黑马点评”作为例子
4.1.发送验证码
Controller
1 2 3 4 5 6 7 8 9 10 11 12
| @Slf4j @RestController @RequestMapping("/user") public class UserController {
@PostMapping("code") public Result sendCode(@RequestParam("phone") String phone, HttpSession session) { return userService.code(phone,session); } }
|
Service
1 2 3
| public interface IUserService extends IService<User> { Result code(String phone, HttpSession session); }
|
ServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
@Override public Result code(String phone, HttpSession session) { boolean phoneInvalid = RegexUtils.isPhoneInvalid(phone); if (phoneInvalid){ return Result.fail("手机号格式错误"); } String code = RandomUtil.randomNumbers(6); session.setAttribute("code",code); log.info("验证码发送成功:"+code); return Result.ok(); }
|
4.2.登录
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Slf4j @RestController @RequestMapping("/user") public class UserController {
@PostMapping("/login") public Result login(@RequestBody LoginFormDTO loginForm, HttpSession session){ return userService.login(loginForm,session); } }
|
Service
1 2 3
| public interface IUserService extends IService<User> { Result login(LoginFormDTO loginForm, HttpSession session); }
|
ServiceImpl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| @Override public Result login(LoginFormDTO loginForm, HttpSession session) { String phone = loginForm.getPhone(); boolean phoneInvalid = RegexUtils.isPhoneInvalid(phone); if (phoneInvalid){ return Result.fail("手机号格式错误"); } String code = (String) session.getAttribute("code"); if (!loginForm.getCode().equals(code)){ return Result.fail("验证码错误"); } LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(User::getPhone, phone); User user = userMapper.selectOne(wrapper); if(user == null){ user = creatUser(phone); } session.setAttribute("user",user);
return Result.ok(); }
private User creatUser(String phone) { User user = User.builder() .phone(phone) .nickName("user_"+RandomUtil.randomString(12)) .build(); userMapper.insert(user); return user; }
|
4.3.登录校验
拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| @Component public class SessionInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); User user = (User) session.getAttribute("user"); if(user==null){ response.setStatus(401); return false; } UserHolder.saveUser(BeanUtil.copyProperties(user,UserDTO.class)); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerInterceptor.super.postHandle(request, response, handler, modelAndView); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { UserHolder.removeUser(); } }
|
注册拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Configuration public class WebConfig extends WebMvcConfigurationSupport { @Resource @Autowired private SessionInterceptor sessionInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(sessionInterceptor) .addPathPatterns("/**") .excludePathPatterns( "/user/login", "/user/code", "/shop/**", "/shop-type/**", "/blog/hot", "/voucher/**", "/session/**" ); } }
|
4.4.测试
完成以上代码后,当访问localhost:8080/login.html
当发送验证码后,来到Redis可以看到,Session以及自动被保存到Redis中了,并且其携带的验证码及其他参数也在其中。
点击登录,登录成功后,User信息也成功存入了Session
5.SpringSession配置
默认的session过期时间为30分钟,即1800s
可以在启动类上的**@EnableRedisHttpSession()** 配置 maxInactiveIntervalInSeconds 属性来设置过期时间,单位为s
如**@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 300)**,那么session的过期时间就是300s