• redis 缓存jwt令牌设置更新时间 BUG修复


    大家好,今天我又又又来了,hhhhh。

    上文中 我们永redis缓存了token 但是我们发现了 一个bug ,redis中缓存的token  是单用户才能实现的。

    就是 我 redis中存储的键 名 为token   值 是jwt令牌 ,但是如果 用户a 登录 之后 创建一个 键 为token的 键值对,如果用户b登录,创建的的键名也是 token ,这样用户b的 jwt 会覆盖 用户a的,就会导致 用户a 的token 会失效呀,这真是一个大大的bug , 按照我目前的水平,我想到了一下 的解决方案 ,既然 token 的键会覆盖,那么我们给 token的键 加上一个唯一标识不就好了  

    解决前的代码

    1. package com.example.getway.globalfilter;
    2. import cn.hutool.core.collection.CollUtil;
    3. import com.example.getway.Untils.JwtUntils;
    4. import com.example.getway.commen.MessageConstant;
    5. import com.example.getway.pojo.JwtProperties;
    6. import io.jsonwebtoken.Claims;
    7. import lombok.RequiredArgsConstructor;
    8. import lombok.extern.slf4j.Slf4j;
    9. import org.springframework.beans.factory.annotation.Autowired;
    10. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    11. import org.springframework.cloud.gateway.filter.GlobalFilter;
    12. import org.springframework.core.Ordered;
    13. import org.springframework.data.redis.core.RedisTemplate;
    14. import org.springframework.http.server.RequestPath;
    15. import org.springframework.http.server.reactive.ServerHttpRequest;
    16. import org.springframework.http.server.reactive.ServerHttpResponse;
    17. import org.springframework.stereotype.Component;
    18. import org.springframework.web.server.ServerWebExchange;
    19. import reactor.core.publisher.Mono;
    20. import javax.annotation.Resource;
    21. import java.util.List;
    22. import java.util.concurrent.TimeUnit;
    23. @RequiredArgsConstructor
    24. @Slf4j
    25. @Component
    26. public class TokenGlobalFilter implements GlobalFilter, Ordered {
    27. private final JwtProperties jwtProperties;
    28. private final RedisTemplate redisTemplate;
    29. // 这个过滤器 请求的转发
    30. @Override
    31. public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    32. //我们只要是非登录请求全都要检验jwt 然后进行 用户信息的传递
    33. //获取request对象
    34. ServerHttpRequest request = exchange.getRequest();
    35. RequestPath requestPath = request.getPath();
    36. if(requestPath.toString().contains("/userLogin")){
    37. return chain.filter(exchange);
    38. }
    39. //获取请求头的 token
    40. // String redisToken =null;
    41. // List authorization = request.getHeaders().get("authorization");
    42. // if (!CollUtil.isEmpty(authorization)) {
    43. // redisToken = authorization.get(0);
    44. // }
    45. String redisToken = (String)redisTemplate.opsForValue().get(MessageConstant.TOKEN);
    46. log.info("token:{}",redisToken);
    47. if (redisToken != null ) {
    48. //进行jwt的解析
    49. try {
    50. Claims claims = JwtUntils.parseJwt(redisToken, jwtProperties.getSecretkey());
    51. //每次 访问其他资源的时候 都把token更新
    52. redisTemplate.expire(MessageConstant.TOKEN, 1000, TimeUnit.DAYS);
    53. String loginId = claims.get(MessageConstant.LOGIN_ID).toString();
    54. log.info("网关层当前用户的id:{}", Long.valueOf(loginId));
    55. //证明 token有效 传递用户信息
    56. ServerWebExchange loginId1 = exchange.mutate()
    57. .request(b -> b.header("loginId", loginId))
    58. .build();
    59. return chain.filter(loginId1);
    60. } catch (Exception e) {
    61. log.info("{}",e.getMessage());
    62. //出现异常返回一个异常响应
    63. ServerHttpResponse response = exchange.getResponse();
    64. response.setRawStatusCode(401);
    65. return response.setComplete();
    66. }
    67. }
    68. log.info("token错误");
    69. return exchange.getResponse().setComplete();
    70. }
    71. //过滤器链中的优先级 数值越低 优先级就越高
    72. @Override
    73. public int getOrder() {
    74. return 0;
    75. }
    76. }

    解决前的登陆代码

    1. package com.example.logindemo.cotroller;
    2. import cn.hutool.core.collection.CollUtil;
    3. import cn.hutool.core.collection.CollectionUtil;
    4. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
    5. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
    6. import com.example.logindemo.Untils.JwtUntils;
    7. import com.example.logindemo.commen.MessageConstant;
    8. import com.example.logindemo.pojo.JwtProperties;
    9. import com.example.logindemo.pojo.po.UserLogin;
    10. import com.example.logindemo.result.Result;
    11. import com.example.logindemo.service.UserLoginService;
    12. import lombok.RequiredArgsConstructor;
    13. import lombok.extern.slf4j.Slf4j;
    14. import org.apache.ibatis.annotations.Param;
    15. import org.springframework.data.redis.core.RedisTemplate;
    16. import org.springframework.util.DigestUtils;
    17. import org.springframework.web.bind.annotation.GetMapping;
    18. import org.springframework.web.bind.annotation.PostMapping;
    19. import org.springframework.web.bind.annotation.RequestMapping;
    20. import org.springframework.web.bind.annotation.RestController;
    21. import java.time.Duration;
    22. import java.util.HashMap;
    23. import java.util.Map;
    24. import java.util.concurrent.TimeUnit;
    25. @RestController
    26. @Slf4j
    27. @RequiredArgsConstructor
    28. public class LoginController {
    29. private final UserLoginService userLoginService;
    30. private final JwtProperties jwtProperties;
    31. private final RedisTemplate redisTemplate;
    32. @PostMapping("/userLogin")
    33. public Result userLogin( String username, String password) {
    34. password=DigestUtils.md5DigestAsHex(password.getBytes());
    35. LambdaQueryWrapper userLoginLambdaQueryWrapper = new LambdaQueryWrapper()
    36. .eq(UserLogin::getUsername, username);
    37. UserLogin userLogin = userLoginService.getOne(userLoginLambdaQueryWrapper);
    38. if(userLogin==null && userLogin.getUsername().isEmpty()){
    39. return Result.error("查询不到用户");
    40. }
    41. if (username.equals(userLogin.getUsername()) && password.equals(userLogin.getPassword())) {
    42. //需要一个map集合 传什么 解析出来什么 一般传的是登录用户的id 我们传1
    43. HashMap map = new HashMap<>();
    44. map.put(MessageConstant.LOGIN_ID, userLogin.getId());
    45. String token = JwtUntils.CreateJwt(map, jwtProperties.getSecretkey());
    46. //设置redis缓存为1000天
    47. redisTemplate.opsForValue().set(MessageConstant.TOKEN,token,1000,TimeUnit.DAYS);
    48. return Result.success(token);
    49. }
    50. return Result.error("未知错误");
    51. }
    52. }

    解决后 的登录代码  这里只放修改部分

    解决后的 网关层过滤代码

    现在 我们手动在数据库添加 一个用户  

    我们apifox进行登录接口的依次登录 ,然后观察 redis中的缓存数据

     发现token 2 存在  我们也就设置成功了

     

  • 相关阅读:
    allegro16.6导出版图到ADS2019仿真的方法
    With As多表查询
    2022.11.5 英语背诵
    C++ 基础入门
    MYSQL 主从不一致的原因分析
    Redis 为什么用跳表,而不用平衡树?
    Servlet的注册和生命周期
    unity打包后无法读取Excel解决方法
    二进制、八进制、十进制、十六进制之间的转换
    阿斯达年代记三强争霸官网地址+游戏账号注册+游戏下载安装教程
  • 原文地址:https://blog.csdn.net/2202_75352238/article/details/139716532