课程名称:SpringBoot 在线协同办公小程序开发 全栈式项目实战
课程章节:刷新token过期时间
课程讲师: 神思者
课程内容:
一、为什么要刷新Token的过期时间?
我们在定义JwtUtil工具类的时候,生成的Token
都有过期时间。那么问题来了,假设Token
过期时间为15天,用户在第14天的时候,还可以免登录正常访问系统。但是到了第15天,用户的Token过期,于是用户需要重新登录系统。
HttpSession
的过期时间比较优雅,默认为15分钟。如果用户连续使用系统,只要间隔时间不超过15分钟,系统就不会销毁HttpSession
对象。JWT的令牌过期时间能不能做成HttpSession
那样超时时间,只要用户间隔操作时间不超过15天,系统就不需要用户重新登录系统。实现这种效果的方案有两种:双Token
和Token缓存
,这里重点讲一下Token
缓存方案。
Token缓存方案是把Token
缓存到Redis,然后设置Redis里面缓存的Token
过期时间为正常Token
的1倍,然后根据情况刷新Token
的过期时间。
Token失效,缓存也不存在的情况
当第15天,用户的Token
失效以后,我们让Shiro程序到Redis查看是否存在缓存的Token
,如果这个Token
不存在于Redis里面,就说明用户的操作间隔了15天,需要重新登录。
Token失效,但是缓存还存在的情况
如果Redis中存在缓存的Token
,说明当前Token
失效后,间隔时间还没有超过15天,不应该让用户重新登录。所以要生成新的Token
返回给客户端,并且把这个Token
缓存到Redis里面,这种操作成为刷新Token
过期时间。
二、客户端如何更新令牌?
在我们的方案中,服务端刷新Token
过期时间,其实就是生成一个新的Token
给客户端。那么客户端怎么知道这次响应带回来的Token是更新过的呢?这个问题很容易解决。
只要用户成功登陆系统,当后端服务器更新Token
的时候,就在响应中添加Token
。客户端那边判断每次Ajax响应里面是否包含Token
,如果包含,就把Token
保存起来就可以了。
三、如何在响应中添加令牌?
我们定义OAuth2Filter
类拦截所有的HTTP请求,一方面它会把请求中的Token
字符串提取出来,封装成对象交给Shiro框架;另一方面,它会检查Token
的有效性。如果Token
过期,那么会生成新的Token
,分别存储在ThreadLocalToken
和Redis
中。
之所以要把新令牌
保存到ThreadLocalToken
里面,是因为要向AOP切面类
传递这个新令牌
。虽然OAuth2Filter
中有doFilterInternal()
方法,我们可以得到响应并且写入新令牌
。但是这个做非常麻烦,首先我们要通过IO流读取响应中的数据,然后还要把数据解析成JSON对象,最后再放入这个新令牌。如果我们定义了AOP切面类
,拦截所有Web方法返回的R对象
,然后在R对象
里面添加新令牌
,这多简单啊。但是OAuth2Filter
和AOP
切面类之间没有调用关系,所以我们很难把新令牌
传给AOP切面类
。
这里我想到了ThreadLocal
,只要是同一个线程,往ThreadLocal
里面写入数据和读取数据是完全相同的。在Web项目中,从OAuth2Filter
到AOP切面类
,都是由同一个线程来执行的,中途不会更换线程。所以我们可以放心的把新令牌保存都在ThreadLocal
里面,AOP切面类
可以成功的取出新令牌,然后往R对象
里面添加新令牌即可。
ThreadLocalToken
是我自定义的类,里面包含了ThreadLocal
类型的变量,可以用来保存线程安全的数据,而且避免了使用线程锁。
课程收获:
今天课程开始初步进入SpringBoot 在线协同办公小程序开发 全栈式项目实战的学习,工欲善其事必先利其器,我们见天开始进行开发环境的准备,今天创建了SSH连接以用来准备接下来一个月的开发,希望打卡可以坚持下去,提升下自己的实战能力和全栈式项目的了解和开发。