JWT TOKEN刷新方案
一、环境
Springboot,Redis
二、需求
最近在做用户中心,需要向其他服务签发JWT Token,使用Token来获取用户信息,保证用户信息安全可靠,不会被重放攻击。
三、问题
JWT Token设置有效期,一旦失效用户就要重新登录,这样的体验非常差,需要做到用户在无感知的情况下,解决如何刷新Token的问题。
四、解决方案
1.设计思路
看了很多文章,大都是通过refresh Token刷新,其实做法上是类似的。
2.Token设计
说明
正常Token:Token未过期,且未达到建议更换时间。
濒死Token:Token未过期,已达到建议更换时间。
正常过期Token:Token已过期,但存在于缓存中。
非正常过期Token:Token已过期,不存在于缓存中。
过期时间
Token过期时间越短越安全,如设置Token过期时间15分钟,建议更换时间设置为Token前5分钟,则Token生命周期如下:
时间 | Token类型 | 说明 |
---|---|---|
0-10分钟 | 正常Token | 正常访问 |
10-15分钟 | 濒死Token | 正常访问,返回新Token,建议使用新Token |
>15分钟 | 过期Token | 需校验是否正常过期。正常过期则能访问,并返回新Token; 非过期Token拒绝访问 |
生成一个正常Token
- 在缓存中,通过用户标识查询老Token。
- 如存在,将老Token(Token,用户标识)本条缓存设置过期时间,作为新老Token交替的过渡期。
- 将新Token以(Token,用户标识)、(用户标识,Token)一对的形式存入缓存,不设置过期时间。
获取一个正常Token
在缓存中,通过用户标识查询用户当前Token,校验该Token是否为正常Token,如正常则返回;不正常则生成一个正常Token。
3.情景
正常Token传入
当正常Token请求时,返回当前Token。
濒死Token传入
当濒死Token请求时,获取一个正常Token并返回。
正常过期Token
当正常过期Token请求时,获取一个正常Token并返回。
非正常过期过期Token
当非正常过期Token请求时,返回错误信息,需重新登录。
4.代码
Maven依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
</dependency>
jwt token工具类
/**
* 获取用户从token中
*/
public String getUserFromToken(String token) {
return getClaimFromToken(token).getSubject();
}
/**
* <pre>
* 验证token是否失效
* true:过期 false:没过期
* </pre>
*/
public Boolean isTokenExpired(String token) {
try {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
} catch (ExpiredJwtException expiredJwtException) {
return true;
}
}
/**
* 获取可用的token
* 如该用户当前token可用,即返回
* 当前token不可用,则返回一个新token
* @param userId
* @return
*/
public String getGoodToken(String userId){
String token = redisTemplate.opsForValue().get("u