Token+Redis登入認證
阿新 • • 發佈:2022-03-10
首發於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有效期