拦截器
拦截器的作用在于将重复的登录校验功能安装在拦截器上(某些请求需要要求用户等登录才能启用)但不可能在每一个业务模块都写校验的代码,于是拦截器的作用就在于拦截请求 去检查用户的状态 是否处于在线 若是在线就刷新token的有效期 token存在Redis中
细节实现就不说了 实现部分的代码
一号拦截器
只需要检查ThreadLocal中是否有用户(有说明登录了,因为登录校验操作中会把用户信息存在ThreadLocal)
Java public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //1.判断是否需要拦截(ThreadLocal中是否有用户) if (UserHolder.getUser() == null) { response.setStatus(401); return false; } return true; } }
二号拦截器
这里我们注入了Redis因为要用Redis来存用户信息
public class RefreshTokeninterceptor implements HandlerInterceptor { //而MvcConfig中使用了 LoginInterceptor 所以我们要去到MvcConfig进行注入 private StringRedisTemplate stringRedisTemplate; //因为这个类不是spring boot构建的,而是手动创建的类,所以依赖注入不能用注解来注入,要我们手动使用构造函数来注入这个依赖 public RefreshTokeninterceptor(StringRedisTemplate stringRedisTemplate) { this.stringRedisTemplate = stringRedisTemplate; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取请求头中的token 在前端代码中详见authorization String token = response.getHeader("authorization"); if(StrUtil.isBlankIfStr(token)){{//判断是否为空 return true; } // 基于token获取Redis用户 String Token = RedisConstants.LOGIN_USER_KEY + token; Map<Object,Object> UserMap = stringRedisTemplate.opsForHash().entries(Token); //判断用户是否存在 if(UserMap.isEmpty()){ return true; } // 将查询到的hash数据转化为userDTO对象 //fillBeanWithMap是用UserMap来填充 UserDTO这个Bean,最后一个参数是你是否忽略转换过程中的错误 UserDTO user = BeanUtil.fillBeanWithMap(UserMap, new UserDTO(), false); //存在 保存用户信息到TheadLocal UserHolder.saveUser(user); //刷新token有效期 stringRedisTemplate.expire(Token,RedisConstants.LOGIN_USER_TTL, TimeUnit.MINUTES); //放行 response.setStatus(200); return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //移除用户 UserHolder.removeUser(); } }
最后是配置拦截器
@Configuration public class MvcConfig implements WebMvcConfigurer { @Resource private StringRedisTemplate stringRedisTemplate; @Override //添加拦截器 InterceptorRegistry registry 拦截器的注册器 excludePathPatterns排除不需要的拦截的路径 // 只要跟登录无关就不需要拦截 拦截器的作用只是校验登录状态 public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .excludePathPatterns( "/user/login", "/user/code", "/blog/hot", "/shop/**", "/shop-type/**", "/voucher/**" ).order(1); //order是设置先后 //刷新token的拦截器 registry.addInterceptor(new RefreshTokeninterceptor(stringRedisTemplate)).addPathPatterns("/**").order(0); } }