前言
token的灵活使用是大家都有所了解的,但是如果指定了token的失效时间过短的话,会造成用户的使用体验大打折扣。假如设定了两小时,两小时内无论做什么动作,时间一到就会失效重新登录。这样太麻烦了,有没有可以让两小时内一旦点击内容或者做了某动作,就会让token的过期时间在那个时间点后面再延长两小时。答案是有的。现在我来说说如何实现。
1.当登录成功时,redis添加key和value值均为token的值
@RestController
public class TestLoginController {
@Resource
private UserMapper1 userMapper1;
@Resource
private RedisUtils redisUtils;
@PostMapping(value = "/login",produces = {"application/json;charset=UTF-8"})
public HashMap<String,Object> login(@RequestBody String json){
JSONObject jsonObject = JSONObject.parseObject(json);
String name = jsonObject.getString("name");
String password = jsonObject.getString("password");
HashMap<String,String> claim = new HashMap<>();
claim.put("name",name);
User user = userMapper1.selectUserByName(name);
HashMap<String,Object> hashMap = new HashMap<>();
if (null == user ){
hashMap.put("rv",400);
hashMap.put("message","登录失败,用户不存在");
return hashMap;
}else{
String token = TokenUtil.createToken(claim);
redisUtils.set(token,token,20);
hashMap.put("token",token);
hashMap.put("rv",200);
hashMap.put("message", "认证成功");
}
return hashMap;
}
}
2.在拦截器配置REDIS续期
@Component
public class TokenInterceptor implements HandlerInterceptor {
@Resource
RedisUtils redisUtils;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle");
if(!(handler instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod = (HandlerMethod)handler;
Method method = handlerMethod.getMethod();
if(method.isAnnotationPresent(PassToken.class)||
handlerMethod.getBeanType().getAnnotation(PassToken.class) != null)
{
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.value()){
return true;
}
}
HashMap<String,String> hashMap = new HashMap<>();
String token = request.getHeader("token");
try {
String redisToken = (String)redisUtils.get(token);
if(StringUtils.hasText(redisToken)){
Integer time = Math.toIntExact(redisUtils.getExpire(token));
if (time>0&&time<10){
System.out.println("续期redis");
redisUtils.expire(redisToken,20);
}
return true;
}
TokenUtil.verifyToken(token);
return true;
}catch (SignatureVerificationException e){
e.printStackTrace();
hashMap.put("msg","签名不一致");
}catch (TokenExpiredException e){
e.printStackTrace();
hashMap.put("msg","令牌过期异常");
}catch (AlgorithmMismatchException e) {
e.printStackTrace();
hashMap.put("msg", "算法不匹配异常");
}catch (InvalidClaimException e){
e.printStackTrace();
hashMap.put("msg","失效的claim异常");
}catch (Exception e){
e.printStackTrace();
hashMap.put("msg","token无效");
}
String resultJson = JSON.toJSONString(hashMap);
response.setContentType("application/json;charset=utf-8");
response.getWriter().print(resultJson);
return false;
}
}
2.1.主要看这一段
String token = request.getHeader("token");
try {
String redisToken = (String)redisUtils.get(token);
if(StringUtils.hasText(redisToken)){
Integer time = Math.toIntExact(redisUtils.getExpire(token));
if (time>0&&time<10){
System.out.println("续期redis");
redisUtils.expire(redisToken,20);
}
return true;
}
解释: 从请求头获取的token的值作为key,在redis查询该key的值。如果存在该key的值,那么抓取该key的过期时间,如果该key的过期时间小于10秒且大于0秒,则帮该key续期20秒。做time>0&&time<10判断过期的时间的原因,是免得redis频繁续期。然后返回true,不拦截该请求。
3.redisUtils工具类部分方法简述
@Resource
private RedisTemplate redisTemplate;
public Object get(String key){
return key == null ? null : redisTemplate.opsForValue().get(key);
}
public boolean set(String key,Object value,long time){
try {
if(time > 0){
redisTemplate.opsForValue().set(key,value,time,TimeUnit.SECONDS);
}else{
set(key,value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public boolean expire(String key,long time){
try {
if(time > 0){
redisTemplate.expire(key,time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public long getExpire(String key){
return redisTemplate.getExpire(key,TimeUnit.SECONDS);
}
项目地址
https://gitee.com/liuweiqiang12/springboot/tree/master/springboot-mybatis-token-redis
如果这篇文章对您有帮助,可否支持一下博主?
点赞+关注呗,谢谢您。
|