首發於Enaium的個人博客
首先需要了解一下大概的步驟
- 登錄生成一個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有效期