摘要:import io.jsonwebtoken.Claims;import io.jsonwebtoken.JwtBuilder;import io.jsonwebtoken.Jwts;import io.jsonwebtoken.SignatureAlgori
自动刷新token是属于后端的解决方案,由后端来检查一个Token的过期时间是否快要过期了,如果快要过期了,就往请求头中重新
放一个token,然后前端那边做拦截,拿到请求头里面的新的token,如果这个新的token和老的token不一致,直接将本地的token更换
接下来拿代码举例子
cn.hutool
hutool-all
5.5.1
com.alibaba
fastjson
1.2.33
io.jsonwebtoken
jjwt
0.9.1
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
publicclass JwtUtil {
// 有效期为
publicstaticfinal Long JWT_TTL = 60 * 60 * 1000 * 24;// 60 * 60 * 1000 * 24 一个小时
// 设置秘钥明文 --- 自己改就行
publicstaticfinal String JWT_KEY = "qx";
// 用于生成uuid,用来标识唯一
public static String getUUID{
String uuid = UUID.randomUUID.toString.replaceAll("-", "");//token用UUID来代替
return uuid;
}
/**
id : 标识唯一
subject : 我们想要加密存储的数据
ttl : 我们想要设置的过期时间
*/
// 生成token jwt加密 subject token中要存放的数据(json格式)
public static String createJWT(String subject) {
JwtBuilder builder = getJwtBuilder(subject, null, getUUID);// 设置过期时间
return builder.compact;
}
// 生成token jwt加密
public static String createJWT(String subject, Long ttlMillis) {
JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID);// 设置过期时间
return builder.compact;
}
// 创建token jwt加密
public static String createJWT(String id, String subject, Long ttlMillis) {
JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间
return builder.compact;
}
private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
SecretKey secretKey = generalKey;
long nowMillis = System.currentTimeMillis;
Date now = new Date(nowMillis);
if(ttlMillis==null){
ttlMillis=JwtUtil.JWT_TTL;
}
long expMillis = nowMillis + ttlMillis;
Date expDate = new Date(expMillis);
return Jwts.builder
.setId(uuid) //唯一的ID
.setSubject(subject) // 主题 可以是JSON数据
.setIssuer("sg") // 签发者
.setIssuedAt(now) // 签发时间
.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
.setExpiration(expDate);
}
// 生成加密后的秘钥 secretKey
public static SecretKey generalKey {
byte encodedKey = Base64.getDecoder.decode(JwtUtil.JWT_KEY);
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
// jwt解密
public static Claims parseJWT(String jwt) throws Exception {
return Jwts.parser
.setSigningKey(secretKey)
.parseClaimsJws(jwt)
.getBody;
}
}
@Test
void test throws Exception {
String token = JwtUtil.createJWT("1735209949551763457");
System.out.println("Token: " + token);
Date tokenExpirationDate = getTokenExpirationDate(token);
System.out.println(tokenExpirationDate);
System.out.println(tokenExpirationDate.toString);
long exp = tokenExpirationDate.getTime;
long cur = System.currentTimeMillis;
System.out.println(exp);
System.out.println(cur);
System.out.println(exp - cur);
}
// 解析令牌并获取过期时间
public static Date getTokenExpirationDate(String token) {
try {
SecretKey secretKey = generalKey;
Claims claims = Jwts.parser
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody;
return claims.getExpiration;
} catch (ExpiredJwtException | SignatureException e) {
thrownew RuntimeException("Invalid token", e);
}
}
Token有点长,就不放全部了
可以看到我们的 exp 过期时间的毫秒数为 1703651262000
可以看到我们的 cur 当前时间的毫秒数为 1703564863035
我们将两者相减得到的值为 86398965ms,我们可以算一下一天的毫秒数是多少 1000 * 60 * 60 * 24 ms = 86400000ms
这样我们就能够拿到token的过期时间tokenExpirationDate了
我们就可以通过在校验token的时候,如果token校验通过了,此时我们拿到该token的过期时间,以(过期时间 - 当前时间)进行判断
如果说 (过期时间 - 当前时间) 小于约定的值,那么我们就重新根据token里面的信息,重新创建一个token,将新的token放到请求头中
返回给前端,前端去进行本地存储更新token
token的续约偏向于前端的解决方案,即由前端来进行token的过期时间的判断,首先前后端需要对接商量好一个token续约的接口,
当前端发现这个token快要过期的时候,向后端发送该token,然后后端将该token的过期时间延长。
「前端采用的是双Token的方式,access-token 和 refresh-token即 AT 和 RT」
「而对于纯后端的方式,就是只有access-token这一个token」
要是前端有一个表单页面,长时间不进行请求的发送,此时用户填写完表单了,再点击提交的时候,后端返回401了,怎么办?
也就是说,虽然你后端可以无感刷新Token,但是你后端无感刷新Token的前提是:前端得发请求,如果用户长时间不进行页面的交互,
即没有进行任何业务逻辑的跳转什么的,就单纯的往表单上面填东西,什么请求也没发的情况下,后端是无法感知Token过期的
「这种情况怎么解决?」
可乐技术交流群开放了!!! 欢迎各位读者进群,群内以技术交流、摸鱼为主,不定期分享有趣有用的工具,以及适合程序员做的副业。 进群 ,我这边拉你进群。来源:寂寞的咖啡