相信很多小伙伴会发现,token这个东西在方便的同时也有一丝丝麻烦(想了解或学习token相关知识请移步:JAVA后端实现JWT令牌_令牌 java-CSDN博客)
原因很简单,其实就是token的过期时间究竟设置多久才算合理,一小时太短,一百年又太长。所以在线续期token是一种很好的解决方案,我的实现思路是:取消原先token自己的过期时长,然后将token存入redis中,key是token,value也是token,存进去什么不重要,重要的是可以根据key去获取value(有效并且没过期),需要的时候随时可以取出来,然后给这个redis一个过期时间,众所周知redis的过期时间是可以重置的,因此在用户每次进行操作的时候就重新给redis一个过期时间即可。大概思路就是这样,醍醐灌顶的小伙伴现在就可以自己去试一下!
这是我们之前的实现思路,也就是给token一个过期时间,然后token过期之后销毁。我们现在吧过期时间直接删掉。
我们现在只在token中放入我们需要的载荷信息以及签名算法。
然后我们需要去修改登录的逻辑,以前是生成一个token返回到前端,现在需要添加一步:将token存入redis中。
这样就实现了redis的储存,现在我们实现续期,我们去修改拦截器的逻辑。
以下是我项目中拦截器的代码:
public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
List<String> asList = Arrays.asList("/login", "/pageHomeImages", "/register", "/doc.html", "/v2", "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
String requestUrl = request.getRequestURI();
log.info("请求的url为:{}", requestUrl);
if (asList.stream().anyMatch(requestUrl::contains)) {
log.info("{}-->已放行", requestUrl);
return true;
}
String token = request.getHeader("token");
log.info("从请求头中获取的令牌:{}", token);
if (!StringUtils.hasLength(token)) {
log.warn("Token不存在");
throw new CustomException(401, Constant.TOKEN_ERROR);
}
try {
if (redisTemplate.opsForValue().get(token) != null) {
Claims claims = JwtUtils.parseJWT(token);
ThreadLocalContext.setUserId(claims.get("id").toString());
redisTemplate.opsForValue().set(token, token, DELAYED_TIME, TimeUnit.SECONDS);
log.info("{}-->已放行", requestUrl);
log.info("用户:{}-->token已在线续期一小时", claims.get("id").toString());
return true;
} else {
log.warn("token已过期");
throw new CustomException(401, Constant.TOKEN_TIMEOUT);
}
} catch (Exception e) {
log.error("token在线续期失败!");
throw new CustomException(401, Constant.USER_STATUS_ERROR);
}
}
至此已全部完成,只要用户有相关操作,即可实现刷新token的效果,在此基础上,还可以实现类似于获取当前过期时间并在此基础上增加时间等效果。