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

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

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

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

解决前的代码

package com.example.getway.globalfilter;

import cn.hutool.core.collection.CollUtil;
import com.example.getway.Untils.JwtUntils;
import com.example.getway.commen.MessageConstant;
import com.example.getway.pojo.JwtProperties;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.server.RequestPath;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
@RequiredArgsConstructor
@Slf4j
@Component
public class TokenGlobalFilter implements GlobalFilter, Ordered {
    private  final JwtProperties jwtProperties;
    private  final   RedisTemplate redisTemplate;
    // 这个过滤器 请求的转发
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //我们只要是非登录请求全都要检验jwt 然后进行 用户信息的传递
       //获取request对象
        ServerHttpRequest request = exchange.getRequest();
        RequestPath requestPath = request.getPath();
        if(requestPath.toString().contains("/userLogin")){
            return  chain.filter(exchange);
        }
        //获取请求头的 token
//        String redisToken =null;
//        List<String> authorization = request.getHeaders().get("authorization");
//        if (!CollUtil.isEmpty(authorization)) {
//            redisToken = authorization.get(0);
//        }

        String redisToken = (String)redisTemplate.opsForValue().get(MessageConstant.TOKEN);
        log.info("token:{}",redisToken);
        if (redisToken != null ) {
            //进行jwt的解析
            try {
                Claims claims = JwtUntils.parseJwt(redisToken, jwtProperties.getSecretkey());
                //每次 访问其他资源的时候 都把token更新
                redisTemplate.expire(MessageConstant.TOKEN, 1000, TimeUnit.DAYS);
                String loginId = claims.get(MessageConstant.LOGIN_ID).toString();
                log.info("网关层当前用户的id:{}", Long.valueOf(loginId));
                //证明 token有效 传递用户信息
                ServerWebExchange loginId1 = exchange.mutate()
                        .request(b -> b.header("loginId", loginId))
                        .build();
                return chain.filter(loginId1);
            } catch (Exception e) {
                log.info("{}",e.getMessage());
                //出现异常返回一个异常响应
                ServerHttpResponse response = exchange.getResponse();
                response.setRawStatusCode(401);
                return  response.setComplete();
            }
        }
        log.info("token错误");
       return  exchange.getResponse().setComplete();
    }
//过滤器链中的优先级 数值越低 优先级就越高
    @Override
    public int getOrder() {
        return 0;
    }
}

解决前的登陆代码

package com.example.logindemo.cotroller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.logindemo.Untils.JwtUntils;
import com.example.logindemo.commen.MessageConstant;
import com.example.logindemo.pojo.JwtProperties;
import com.example.logindemo.pojo.po.UserLogin;
import com.example.logindemo.result.Result;
import com.example.logindemo.service.UserLoginService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Param;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
@RequiredArgsConstructor
public class LoginController {
    private  final UserLoginService userLoginService;
    private final JwtProperties jwtProperties;
    private  final RedisTemplate redisTemplate;
    @PostMapping("/userLogin")
    public Result userLogin( String username,  String password) {
          password=DigestUtils.md5DigestAsHex(password.getBytes());
        LambdaQueryWrapper<UserLogin> userLoginLambdaQueryWrapper = new LambdaQueryWrapper<UserLogin>()
                .eq(UserLogin::getUsername, username);
        UserLogin userLogin = userLoginService.getOne(userLoginLambdaQueryWrapper);
        if(userLogin==null && userLogin.getUsername().isEmpty()){
            return Result.error("查询不到用户");
        }
        if (username.equals(userLogin.getUsername()) && password.equals(userLogin.getPassword())) {
         //需要一个map集合  传什么 解析出来什么   一般传的是登录用户的id  我们传1
            HashMap<String, Object> map = new HashMap<>();
            map.put(MessageConstant.LOGIN_ID, userLogin.getId());
            String token = JwtUntils.CreateJwt(map, jwtProperties.getSecretkey());
            //设置redis缓存为1000天
            redisTemplate.opsForValue().set(MessageConstant.TOKEN,token,1000,TimeUnit.DAYS);
            return Result.success(token);
        }
        return Result.error("未知错误");
    }

}


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

解决后的 网关层过滤代码

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

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

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

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/714727.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode43.字符串相乘【大整数相乘】

LeetCode刷题记录 文章目录 &#x1f4dc;题目描述&#x1f4a1;解题思路 &#x1f4dc;题目描述 给定两个以字符串形式表示的非负整数 num1 和 num2&#xff0c;返回 num1 和 num2 的乘积&#xff0c;它们的乘积也表示为字符串形式。 注意&#xff1a;不能使用任何内置的 Big…

C++ 算法教程

归并排序 #include<iostream> using namespace std; template <class T> void Merge(T data[],int start,int mid,int end) {int len1 mid - start 1, len2 end - mid;int i, j, k;T* left new int[len1];T* right new int[len2];for (i 0; i < len1; i)…

数据结构--力扣104,110 二叉树相关(C

1.力扣104。二叉树的最大深度-. - 力扣&#xff08;LeetCode&#xff09; 2.力扣110。平衡二叉树->. - 力扣&#xff08;LeetCode&#xff09; 1. 叶子结点 指&#xff1a;没有子节点的节点 思路&#xff1a; 求其 左子树和右子树的最大深度&#xff0c;返回其中最大值即可…

《C语言》文件操作

文章目录 一、认识文件1、文件的概念2、程序文件3、数据文件4、文件名 三、二进制文件和文本文件四、文件的打开和关闭1、流2、标准流3、文件指针4、文件的关闭和打开 四、文件的顺序读写文件的随机读写1、fseek2、ftell3、rewind4.int origin 一、认识文件 主要讨论数据文件 1…

C++ 矩阵乘法

描述 如果A是个x行y列的矩阵&#xff0c;B是个y行z列的矩阵&#xff0c;把A和B相乘&#xff0c;其结果将是另一个x行z列的矩阵C。这个矩阵的每个元素是由下面的公式决定的 矩阵的大小不超过100*100 输入描述&#xff1a; 第一行包含一个正整数x&#xff0c;代表第一个矩阵的…

Go如何在本地引用以及发布并引用自定义工具包

如何引用本地自定义工具包 我们首先要准备两个项目&#xff0c;分别为需要引入的工具包和当前项目。 myutils、myproject1. myutils为我们的项目1-工具包 package mypakgeimport "strings"func IsContains(s string) bool {if strings.Contains(s, "a")…

Java面向对象-接口

Java面向对象-接口 一、JDK1.8之前二、接口的作用三、JDK1.8之后&#xff0c;新增非抽象方法四、静态方法 一、JDK1.8之前 1、类是类&#xff0c;接口是接口&#xff0c;它们是同一层次的概念 2、接口中没有构造器 3、接口如何声明&#xff1a;interface 4、在jdk1.8之前&…

二分查找-java代码实现(easy)

目录 一、问题描述 二、代码实现 三、刷题链接 一、问题描述 二、代码实现 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可** 如果目标值存在返回下标&#xff0c;否则返…

STM32理论 —— μCOS-Ⅲ(2/2):时间管理、消息队列、信号量、任务内嵌信号量/队列、事件标志、软件定时器、内存管理

文章目录 9. 时间管理9.1 OSTimeDly()9.2 OSTimeDlyHMSM()9.3 OSTimeDlyResume()9.4 延时函数实验 10. 消息队列10.1 创建消息队列函数OSQCreate()10.2 发送消息到消息队列函数(写入队列)OSQPost()10.3 获取消息队列中的消息函数(读出队列)OSQPend()10.4 消息队列操作实验 11. …

使用React和GraphQL进行CRUD:完整教程与示例

在本教程中&#xff0c;我们将向您展示如何使用GraphQL和React实现简单的端到端CRUD操作。我们将介绍使用React Hooks读取和修改数据的简单示例。我们还将演示如何使用Apollo Client实现身份验证、错误处理、缓存和乐观UI。 什么是React&#xff1f; React是一个用于构建用户…

Unity 3D 物体的Inspector面板

1、Transform&#xff1a;位置、旋转、大小 2、Mesh Filter&#xff1a;物体的形状 3、Mesh Renderer&#xff1a;物体渲染&#xff08;物体的衣服&#xff09; 4、Collider&#xff1a;碰撞体

PyTorch计算机视觉入门:测试模型与评估,对单帧图片进行推理

在完成模型的训练之后&#xff0c;对模型进行测试与评估是至关重要的一步&#xff0c;它能帮助我们理解模型在未知数据上的泛化能力。本篇指南将带您了解如何使用PyTorch进行模型测试&#xff0c;并对测试结果进行分析。我们将基于之前训练好的模型&#xff0c;演示如何加载数据…

Electron无感打印 静默打印(vue3 + ts + vite)

&#xff08;electron vue3 项目搭建部分 自行查找其他资源 本文只讲解Electronvue3 如何实现静默打印&#xff09; 第一步获取打印机资源 渲染端代码&#xff08;vue里面&#xff09; // 因使用了vite所以在浏览器中打开 require会报错 只能在electron中 const { ipcRender…

【gitcode】idea 在本地拉取和push本地代码到gitcode仓库

【首次使用】 1、idea 拉取代码&#xff0c;很容易这里就不记录了。 2、push代码时&#xff0c;总是弹窗登录输入在gitcode.com登录能成功。但是在idea 怎么都不成功。控制台提示 remote: HTTP Basic: Access denied fatal: Authentication failed for ******* 认证失败 3…

仲恺ZK——信计专业《软件体系结构》24年试卷回忆

以下是我在总结的复习内容&#xff0c;有需要可以参考借鉴一下。我的主页还有另外一篇复习总结《仲恺ZK——信计专业《软件体系结构》&#xff0c;两者结合起来复习&#xff0c;帮助你轻松过考试&#x1f60a;。总的来说&#xff0c;考试不会太难&#xff0c;只要你了解了各类设…

QuickLook最强大的C#开源文件预览神器

功能特点&#xff1a; 快速预览&#xff1a;用户只需选中文件并按下空格键&#xff0c;即可立即查看文件内容&#xff0c;无需打开特定应用程序或软件。 多格式支持&#xff1a;QuickLook支持预览几乎所有常见的文件类型&#xff0c;包括但不限于&#xff1a; 图像&#xff1…

SwiftUI 6.0(iOS 18)新容器视图修改器漫谈

概览 本届 WWDC 2024 观影正如火如荼的进行中&#xff0c;一片鸟语花香、枝繁叶茂的苹果树上不时结出几颗令人垂涎欲滴的美味苹果让秃头码农们欲罢不能。 如您所愿&#xff0c;在界面布局“利器” SwiftUI 这根蔓藤也长出不少喜人的果实&#xff0c;其中在 iOS 18.0 中新添加的…

mybatis-plus使用拦截器实现sql完整打印

shigen坚持更新文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 个人IP&#xff1a;shigen 在使用mybatis-plus&#xff08;mybatis&#xff09;的时候&#xff0c;往往需要…

IT人的拖延——这个任务太复杂,太难了怎么办?

随着科技的发展&#xff0c;IT人需要不断地运用新技术来解决更多传统方式难以解决的问题&#xff0c;有些问题真的不是不想解决&#xff0c;而是真的太复杂&#xff0c;太难了&#xff0c;根本不知道从何开始&#xff0c;也没有什么前辈的经验可以借鉴。我们这些对事情难度的认…

奇思妙想-可以通过图片闻见味道的设计

奇思妙想-可以通过图片闻见味道的设计 偷闲半日享清闲&#xff0c;炭火烧烤乐无边。肉串飘香引客至&#xff0c;笑语欢声绕云间。人生难得几回醉&#xff0c;且把烦恼抛九天。今宵共饮开怀酒&#xff0c;改日再战新篇章。周四的傍晚&#xff0c;难得的闲暇时光让我与几位挚友相…