1
2
3
4
5
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package com.zdong.dream.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.zdong.dream.common.CodeEnum;
import com.zdong.dream.exception.MyException;
import com.zdong.dream.vo.UserVO;
import io.jsonwebtoken.*;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Objects;
import java.util.UUID;

/**
* @author : zdong
* @date : Created in 2022/7/27 10:59
* @description
*/
public class JwtUtil {

private static final long tokenExp = 1000 * 60 * 60 * 24; // 一天
private static final String tokenSignKey = "TEST123";
private static final Long bufferTime = 24L; // 缓冲时间(单位小时)
// 错误代码
private static final CodeEnum expire= CodeEnum.TOKEN_EXPIRE; // token已过期
private static final CodeEnum invalid= CodeEnum.TOKEN_INVALID; // token已过期

/**
* 构建jwt
* @param user 用户信息
* @return jwt
*/
public static String builder(UserVO user){
JwtBuilder builder = Jwts.builder();
return builder
// 头部信息
.setHeaderParam("alg","SH256")
.setHeaderParam("typ","JWT")
// 载荷:自定义信息
.claim("user",user)
// 载荷:固定信息
.setSubject("default") // sub:令牌主题
.setIssuer("dream") // iss:签发这
.setAudience("aud") // aud:接收者
.setIssuedAt(new Date()) // jat:签发时间
.setExpiration(new Date(System.currentTimeMillis() + tokenExp)) // exp:过期时间
.setNotBefore(new Date()) // nbf:生效时间
.setId(UUID.randomUUID().toString()) // jti:唯一身份标识,主要用来回避重放攻击
// 签名哈希
.signWith(SignatureAlgorithm.HS256,tokenSignKey)
.compact();
}

/**
* 构建jwt:主要用户未登录状态下,绑定手机号时的身份验证。
* @param uid 用户id
* @return jwt
*/
public static String builder(Long uid){
long tokenExp = 1000 * 60 * 10; // 10分钟
JwtBuilder builder = Jwts.builder();
return builder
// 头部信息
.setHeaderParam("alg","SH256")
.setHeaderParam("typ","JWT")
// 载荷:自定义信息
.claim("uid",uid)
// 载荷:固定信息
.setSubject("default") // sub:令牌主题
.setIssuer("dream") // iss:签发这
.setAudience("aud") // aud:接收者
.setIssuedAt(new Date()) // jat:签发时间
.setExpiration(new Date(System.currentTimeMillis() + tokenExp)) // exp:过期时间
.setNotBefore(new Date()) // nbf:生效时间
.setId(UUID.randomUUID().toString()) // jti:唯一身份标识,主要用来回避重放攻击
// 签名哈希
.signWith(SignatureAlgorithm.HS256,tokenSignKey)
.compact();
}


/**
* 验证token
* @param token jwt
* @return 用户信息
*/
public static UserVO verify(String token){
JwtParser parser = Jwts.parser();
try{
Jws<Claims> claimsJws = parser.setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims body = claimsJws.getBody();
Object user = body.get("user");
return BeanUtil.copyProperties(user, UserVO.class);
}catch (ExpiredJwtException e){
// token已过期
Claims claims = e.getClaims();
Date expiration = claims.getExpiration();
long between = DateUtil.between(DateUtil.date(), expiration, DateUnit.HOUR);
if(bufferTime>between){
// 如果过期时间没有超过缓冲时间,那么放行本次请求,并返回错http错误代码299,让前端及时获取新的jwt
HttpServletResponse response =((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getResponse();
assert response != null;
response.setStatus(CodeEnum.HTTPCODE_BUFFER.getCode());
Object user = claims.get("user");
return BeanUtil.copyProperties(user, UserVO.class);
}else{
// 过期时间超过缓冲期,抛出异常
throw new MyException(expire);
}
}catch (MalformedJwtException e){
// 无效token
throw new MyException(invalid);
}
}

/**
* 验证token 严格模式(没有缓存时间)
* @param token jwt
* @return 用户id
*/
public static Long verifyStrict(String token){
JwtParser parser = Jwts.parser();
try {
Jws<Claims> claimsJws = parser.setSigningKey(tokenSignKey).parseClaimsJws(token);
Claims claims = claimsJws.getBody();
return claims.get("uid", Long.class);
}catch (ExpiredJwtException e){
throw new MyException(CodeEnum.TIMEOUT);
}


}

}