【shiro】问题记录--为什么refreshToken方法走不下去

news2024/12/24 2:07:56

一、前言

最近做Jwt token续签的时候,在很多博客和下载的代码中,都是在JWTFilter中进行token的刷新,于是就按照了网上的代码进行尝试,代码如下:

1. 代码

  1. 在JWTFilter中的isAccessAllowed方法
    目的:就是想通过executeLogin内部的方法,出现了token过期,然后返回TokenExpiredException的异常,就进行refreshToken
 @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        //判断请求的请求头是否带上 "Token"
        if (isLoginAttempt(request, response)){
        	// 省略一些其他操作,主要看以下核心内容
			try {
                 //如果存在,则进入 executeLogin 方法执行登入,检查 token 是否正确
                 executeLogin(request, response);
                 return true;
             }catch (Exception e){
                 /*
                  * 注意这里捕获的异常其实是在Realm抛出的,但是由于executeLogin()方法抛出的异常是从login()来的,
                  * login抛出的异常类型是AuthenticationException,所以要去获取它的子类异常才能获取到我们在Realm抛出的异常类型。
                  * */
                 Throwable cause = e.getCause();
                 if (cause!=null&&cause instanceof TokenExpiredException){
                     //AccessToken过期,尝试去刷新token
                     String result = refreshToken(request, response);
                     if (result.equals("success")) {
                         return true;
                     }
                 }
             }
		}
    	return false;
    }        
  1. 在JWTFilter中的refreshToken方法
    目的:刷新token,进行续签。
    PS:这里主要说问题,不做详细说明
	@Autowired
    @Lazy
    private RedisUtil redisUtil;
    
	private Boolean refreshToken(ServletRequest request,ServletResponse response) {
        HttpServletRequest req= (HttpServletRequest) request;
        // 获取传递过来的accessToken
        // 从请求头header中获取字段名为ACCESS_TOKEN的值(也就是我们说的token)
        String token = req.getHeader(CommonConstant.ACCESS_TOKEN);
        // redis中的token 定义前缀+token 为缓存中的key,得到对应的value(cacheToken)
        Object cacheToken = redisUtil.get(CommonConstant.PREFIX_USER_TOKEN + token);

        // 获取token里面的用户名
        String userName = JwtUtil.getUsername(token);

        // 判断refreshToken是否过期了,如果过期了,redis的key将不存在
        if (CommonUtils.isNotEmpty(cacheToken)){
			...
		}

2. 设置

使用的依赖:

		<dependency>
			<groupId>com.auth0</groupId>
			<artifactId>java-jwt</artifactId>
			<version>3.2.0</version>
		</dependency>

为了测试这部分正常使用,设置了token的签证过期时间为1分钟,redis中存储token的过期时间也为1分钟。

PS:看网上都是这样设置的。

二、问题

1. 问题一:e.getCause()获取不到TokenExpiredException

登录获取token后,过了1分钟,在访问接口,断点打在了Throwable cause = e.getCause();,查看捕获的异常为org.apache.shiro.authc.UnknownAccountException: Realm,如下:
在这里插入图片描述
翻译过来就是:找不到提交的AuthenticationToken的帐户数据。
想到token过期就1分钟,好像也对,redis存的过期,token也过期,但是为啥没有获取到TokenExpiredException这个异常?
TokenExpiredException:token过期而抛出的异常。

2. 问题二:refreshToken方法走不下去

  1. 为什么redisUtil为null
  2. 即使redisUtil不为null,但cacheToken也为null

在这里插入图片描述

三、查看源码

  • 从executeLogin往下看源码(问题二)
    这个的代码,主要是执行了Subject接口中的login,详细的可以看下==【shiro】subject.login(token)源码== 这篇文章,这里给出流程图:
    在这里插入图片描述基于以上文章的内容,快步查看源码。

根据 问题 中的截图,对着下面subject.login(token)的流程查看报错信息在哪输出,最后发现在ModularRealmAuthenticator类中。
在这里插入图片描述
该异常主要是因为info返回值为null,具体看下AuthenticationInfo info = realm.getAuthenticationInfo(token);
在这里插入图片描述
这个类大家应该都很熟悉了,看到doGetAuthenticationInfo就是我们在realm中重写的身份验证方法。
这个类中要得到info返回值为null,那就得看getCachedAuthenticationInfo(token)方法。
在这里插入图片描述
在该方法中,主要判断cachetoken是否为null,如果为null那info只能返回null。
PS:这个地方还是有点迷,debug进来会发现,redis即使没有过期,这里的cache还是为null,而且这地方为null,整个流程其实还是正常进行。(这里点以后遇到在继续研究)

四、总结

redis和token同时过期,以上代码就没法进行token续签了。

  1. 问题一
    主要原因是token过期,所以查不到信息,导致返回org.apache.shiro.authc.UnknownAccountException: Realm
    解决一:redis中token过期时间设为20分钟,token签证的过期时间设为1分钟,将两个时间错开可以执行,再去实验,就可以得到TokenExpiredException的异常了。(具体没再往下深究)
  2. 问题二
    2.1 原因:拦截器在bean初始化前执行的,这时候redisUtil是null,需要通过SpringUtils进行反射获取
    2.2 原因:token过期了(问题一中同样的问题)
    解决二:将两个时间错开

PS:全是个人理解,请大佬们指导一下👀

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32单片机RS485远程PID直流电机调速系统光电传感器

实践制作DIY- GC0137-RS485远程PID直流电机调速系统 基于STM32单片机设计-RS485远程PID直流电机调速系统 二、功能介绍&#xff1a; 主机&#xff1a;STM32F103C系列最小系统LCD1602直流电机光电测速MX15系列驱动模块4*4矩阵键盘RS485收发电路 从机&#xff1a;STM32F103C系…

Kubernetes配置管理

1. ConfigMap简介 Kubernetes ConfigMap是一种用于存储应用程序配置信息的对象。在企业中&#xff0c;我们通常会有许多不同的应用程序&#xff0c;每个应用程序都需要一些配置信息&#xff0c;例如数据库连接字符串、API密钥等等。这些配置信息可能会因为环境的不同而有所不同…

JavaSE进阶(day12,复习自用)

网络编程&#xff08;通信&#xff09; 网络通信三要素三要素概述、要素一&#xff1a;IP地址IP地址操作类-InetAddress要素二&#xff1a;端口号要素三&#xff1a;协议 UDP通信-快速入门UDP通信-广播、组播TCP通信-快速入门编写客户端代码编写服务端代码、原理分析 TCP通信-多…

30天从入门到精通TensorFlow1.x 第四天,TensorFlow中的计算图或数据流图

文章目录 一、接前一天二、计算图或数据流图1. 什么是计算图或者数据流图2. 为什么需要计算图或者数据流图3. 执行顺序和延迟加载在tf中的使用 一、接前一天 这几天主要学习了张量的创建方法&#xff0c;以及变量&#xff0c;变量命名域共享变量等概念。今天主要熟悉 数据流图…

网络隔离的生物制药企业,怎样实现安全的跨网文件交换?

在数字时代&#xff0c;生物制药企业结合现代技术追求和实现生物科技领域上的突破&#xff0c;研发及生产出更多满足人体健康需求的药物及医疗技术。由于生物制药企业&#xff0c;在进行某一领域的科研时通常周期较长、且涉及很多创新性成果&#xff0c;因此&#xff0c;科研数…

css:CSS 线性渐变linear-gradient

CSS 渐变使您可以显示两种或多种指定颜色之间的平滑过渡。 CSS 定义了两种渐变类型&#xff1a; 线性渐变&#xff08;向下/向上/向左/向右/对角线&#xff09;径向渐变&#xff08;由其中心定义&#xff09; 参考文档 CSS 线性渐变 https://www.w3school.com.cn/css/css3_…

访问学者带孩子去美国何时入境最好?

访问学者带孩子去美国入境的最佳时间会受到多种因素的影响&#xff0c;例如孩子的学校安排、访问学者的工作计划以及家庭的个人喜好。然而&#xff0c;以下是知识人网小编整理的一些常见考虑因素&#xff1a; 1. 学校假期&#xff1a;如果孩子正在就读学校&#xff0c;最佳时间…

uniapp 打包app wgt热更新和整包更新以及更新弹窗动画

app热更新是app项目最常见的功能&#xff0c;接下来我总结了当时做这个功能的过程&#xff0c;来交流学习一哈 热更新的流程步骤 在用户进入app就获取当前版本号与调用后端接口返回的版本号对比是否是最新的版本不是最新弹出弹窗让用户确认是否更新&#xff0c;点击更新下载w…

财务创造价值,如何降本增效?

一、整体成本管控理论 有财务人员可能认为这和我们财务有什么关系&#xff0c;这和财务管理也没有关系。我们经常提到的业务财融合以及成本BP&#xff0c;其实在这里面是需要发挥应有的价值的。如何理解这个问题&#xff1f;无论是老板还是财务人员&#xff0c;一是有财务管理…

2023年测试人前景归途?我主攻自动化测试拿到了25k的offer...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…

LeetCode_双指针_中等_86.分隔链表

目录 1.题目2.思路3.代码实现&#xff08;Java&#xff09; 1.题目 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。你应当保留两个分区中每个节点的初始相对位置。 示例 1&…

JavaEE(系列19) -- 计算机网络初识

目录 1. 网络发展史 2. IP地址和端口号 3. 协议 4. 五元组 6. 协议分层 6.1 OSI 七层模型 6.2 TCP/IP五层&#xff08;或四层&#xff09;模型 7. 协议分层(网络数据传输过程) 7.1 应用层 7.2 传输层(进入了操作系统内核) 7.3 网络层 7.4 数据链路层 7.5 物理层 声明:本文内…

【CSS3+HTML5+JQUERY】------ 实现环形进度条实例代码-(已简单封装)

1. JavaScript代码 circle.js文件: 简单的封装了一下 直接调用方法即可 (function ($$) {var lyCircle {};lyCircle.options{timer:20,circleLeft:.ly-circle-left,elements:"",circleRight:".ly-circle-right",percentSum:0,//百分比bgColor:#00a7ff,bor…

stable diffusion中的u net

Stable Diffusion 包含几个核心的组件&#xff1a; 一个文本编码器&#xff08;在 Stable Diffusion 中使用 CLIP 的 ViT-L/14 的文本编码器&#xff09;&#xff0c;用于将用户输入的 Prompt 文本转化成 text embedding&#xff1b;一个 Image Auto Encoder-Decoder&#xff…

大模型核心技术原理: Transformer架构详解

在大模型发展历程中&#xff0c;有两个比较重要点&#xff1a;第一&#xff0c;Transformer 架构。它是模型的底座&#xff0c;但 Transformer 不等于大模型&#xff0c;但大模型的架构可以基于 Transformer&#xff1b;第二&#xff0c;GPT。严格意义上讲&#xff0c;GPT 可能…

【学习笔记】Python核心技术与实战-基础篇-03列表和元组,到底用哪个?

目录 列表和元组基础概念区别列表和元组的基础操作和注意事项列表和元组存储方式的差异列表和元组的性能列表和元组的使用场景总结思考题 列表和元组基础 概念 列表和元组&#xff0c;都是一个可以放置任意数据类型的有序集合。 在绝大多数编程语言中&#xff0c;集合的数据类…

C++算法:排序之二(归并、希尔、选择排序)

C算法&#xff1a;排序 排序之一&#xff08;插入、冒泡、快速排序&#xff09; 排序之二&#xff08;归并、希尔、选择排序&#xff09; 文章目录 C算法&#xff1a;排序二、比较排序算法实现4、归并排序5、希尔排序5、选择排序 原创文章&#xff0c;未经许可&#xff0c;严禁…

从vue2到vue3的生命周期

1.vue2 在vue2.x中的生命周期为 beforeCreate created beforeMount mounted beforeUpdate updated beforeDestroy destroyed activated deactivated errorCaptured 在vue3中&#xff0c;新增了一个setup生命周期函数&#xff0c;setup执行的时机是在beforeCreate生命函数之前…

count(0)、count(1)和count(*)、count(列名) 的区别

当我们对一张数据表中的记录进行统计的时候&#xff0c;习惯都会使用 count 函数来统计&#xff0c;但是 count 函数传入的参数有很多种&#xff0c;比如 count(1)、count(*)、count(字段) 等。 到底哪种效率是最好的呢&#xff1f;是不是 count(*) 效率最差&#xff1f; 一.…

【Mysql数据库从0到1】-入门基础篇--sql语句简单使用

【Mysql数据库从0到1】-入门基础篇--sql语句简单使用 &#x1f53b;一、数据库创建、删除、选择1.1 &#x1f343; create database 创建数据库1.2 &#x1f343; 使用 mysqladmin 创建数据库1.3 &#x1f343; drop 命令删除数据库--一般不建议在数据库执行delete、drop等命令…