Token+Redis登录认证
首先需要了解一下大概的步骤
- 登录生成一个Token存入Redis有效期为30分钟,返回到前端
- 之后前端每次请求,带上登录时返回的Token
- 服务器判断前端带来的Token是否在Redis服务器中
- 存在放行并且重置Token有效期,不存在拦截
一个简简单单的登录请求
@RequestMapping("/login")
@ResponseBody
public Result<String> login(@RequestBody UserDTO userDTO) {
var byUsernameAndPassword = mapper.getByUsernameAndPassword(userDTO.getUsername(), userDTO.getPassword());
if (byUsernameAndPassword != null) {
return new Result<>(true, "login success");
}
return new Result<>(false, "wrong username or password");
}
生成一个UUID存入Redis,值为用户的ID,并且设置有效期为30分钟
var uuid = "user-token:" + UUID.randomUUID();
redisTemplate.opsForValue().set(uuid, byUsernameAndPassword.getId().toString(), 30, TimeUnit.MINUTES);
return new Result<>(true, uuid);
接下来直写拦截器,重写addInterceptors方法
@Configuration
public class RequestInterceptor implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
}
}
使用HandlerInterceptor重写preHandle方法,登录和注册不用拦截
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return false;
}
}).excludePathPatterns("/user/login", "/user/register");
前端在请求头中放入Token,之后从请求头中获取Token,从Redis中获取token是否存在,存在返回为true并且重新设置有效期,不存在就返回false设置响应状态为401
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
var token = request.getHeader("token");
if (token != null && redisTemplate.opsForValue().get(token) != null) {
redisTemplate.expire(token, 30, TimeUnit.MINUTES);
return true;
}
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
到这里一个简简单单的Token登录认证就完成了,不过还有个小问题,那就是只有访问需要拦截的地址时,有效期才会被重置,用户一直访问不需要拦截的地址,Token有效期那就不会被重置,所以解决方法也很简单,那就是在登录认证的拦截器之前再加一个拦截器,用来刷新Token有效期