springboot实现token

First Post:

Last Update:

Word Count:
1.1k

Read Time:
6 min

1.导入依赖

1
2
3
4
5
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.18.1</version>
</dependency>

application.yml配置

1
2
3
enroll:
token:
secret: '5xcJVrXNyQDIxK1l2RS9nw'

2.拦截器配置

CertificationInterceptor

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
Slf4j
@Component
public class CertificationInterceptor implements HandlerInterceptor {

@Autowired
private UserDao userDao;

@Autowired
private TokenDao tokenDao;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!HttpMethod.OPTIONS.matches(request.getMethod())) {
String tokenString = request.getHeader("token");

if (StrUtil.isEmpty(tokenString)) {
return false;
}

int userId = -1;
try {
userId = TokenUtils.verify(tokenString);
} catch (TokenExpiredException e) {
return false;
} catch (Exception e) {
return false;
}

Token token = tokenDao.selectByTokenString(tokenString);//数据库查询token
if (token == null || token.getUserId() != userId || token.getExpired().getTime() < System.currentTimeMillis()) {
// 无效的token
return false;
}
}
return false;
}

WebConfig

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
@Slf4j
@Component
public class WebConfig implements WebMvcConfigurer {

@Autowired
private CertificationInterceptor certificationInterceptor;

/**
* 拦截器配置
*
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(certificationInterceptor)
.addPathPatterns("/user/**", "/resource/**")
.excludePathPatterns("/file/**",
"/user/auth",
"/user/checkEnrollToken",
"/user/admin/auth",
"/user/getAccessToken",
"/user/getToken",
"/user/getTokenTest",
"/user/checkPhone",
"/user/checkSid",
"/user/search",
"/resource/dynamic/**",
)
.order(0)
;
}

TokenUtils

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
@Slf4j
@Component
public class TokenUtils {

/**
* 默认过期时间(7天)
*/
private static final long EXPIRE_TIME = 7 * 24 * 60 * 60 * 1000L;

/**
* 加密私钥
*/
private static String tokenSecret;

public TokenUtils(@Value(value = "${enroll.token.secret}") String tokenSecret) {
TokenUtils.tokenSecret = tokenSecret;
}

/**
* 创建token(默认过期时间为24小时)
*
* @param userId 用户id
* @return
*/
public static Token createToken(int userId) {
Date expired = new Date(System.currentTimeMillis() + EXPIRE_TIME);
return createTokenAndSpecifyExpirationTime(userId, expired);
}

/**
* 创建token并指定过期时间
*
* @param userId 用户id
* @param expirationTime 过期时间
* @return
*/
public static Token createTokenAndSpecifyExpirationTime(int userId, Date expirationTime) {
Date createTime = new Date();
//根据用户id,加密生成真正的token字符串
String tokenString = generateTokenString(userId, expirationTime);

Token token = new Token();
token.setUserId(userId);
token.setExpired(expirationTime);
token.setToken(tokenString);
token.setStatus(TokenStatusEnum.EFFICIENT.getStatus());
token.setCreateTime(createTime);
token.setUpdateTime(createTime);

return token;
}

/**
* 验证token是否有效
*
* @param tokenString
*/
public static int verify(String tokenString) {
Algorithm algorithm = Algorithm.HMAC256(tokenSecret);
//根据algorithm创建JWT校验器
JWTVerifier verifier = JWT.require(algorithm).build();
//对token进行解码
DecodedJWT decodedJWT = verifier.verify(tokenString);
//获取负载payload
//String payload = decodedJWT.getPayload();
//String decodeStr = Base64.decodeStr(payload);
//Map<String, Object> objectMap = JsonUtils.quietlyDeserializeForMap(decodeStr);
Claim userId = decodedjwt.getClaim("userId");
//Integer userId = (Integer) objectMap.get("userId");
Integer userId = (Integer) userId.asString();

return userId != null ? userId : -1;
}

/**
* 根据用户id,加密生成真正的token字符串
*
* @return
*/
private static String generateTokenString(int userId, Date expired) {
//加密tokenSecret
Algorithm algorithm = Algorithm.HMAC256(tokenSecret);

Map<String, Object> header = new HashMap<>(2);
header.put("typ", "JWT");
header.put("alg", "HS256");

return JWT.create()
.withHeader(header)
.withIssuer("xue") //token的签发人
.withClaim("userId", userId)
// 防止并发时,生成相同的token
.withClaim("safe-code", UUID.randomUUID().toString().replace("-", ""))
.withExpiresAt(expired) //添加过期时间
.sign(algorithm); //添加私钥
}

/**
* 判断token是否过期
*
* @return
*/
public static boolean isExpiresAt(String tokenString){
Algorithm algorithm = Algorithm.HMAC256(tokenSecret);

JWTVerifier verifier = JWT.require(algorithm).build();

DecodedJWT decodedJWT = verifier.verify(tokenString);

Date expiresAt = decodedJWT.getExpiresAt();

Date day=new Date();
//day小于expiresAt时返回True
return day.before(expiresAt);
}
}

第二种

AppJwtUtil

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
import io.jsonwebtoken.*;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;

public class AppJwtUtil {

// TOKEN的有效期一天(S)
private static final int TOKEN_TIME_OUT = 3_600;
// 加密KEY
private static final String TOKEN_ENCRY_KEY = "MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY";
// 最小刷新间隔(S)
private static final int REFRESH_TIME = 300;

// 生产ID
public static String getToken(Long id){
Map<String, Object> claimMaps = new HashMap<>();
claimMaps.put("id",id);
long currentTime = System.currentTimeMillis();
return Jwts.builder()
.setId(UUID.randomUUID().toString())
.setIssuedAt(new Date(currentTime)) //签发时间
.setSubject("system") //说明
.setIssuer("heima") //签发者信息
.setAudience("app") //接收用户
.compressWith(CompressionCodecs.GZIP) //数据压缩方式
.signWith(SignatureAlgorithm.HS512, generalKey()) //加密方式
.setExpiration(new Date(currentTime + TOKEN_TIME_OUT * 1000)) //过期时间戳
.addClaims(claimMaps) //cla信息
.compact();
}

/**
* 获取token中的claims信息
*
* @param token
* @return
*/
private static Jws<Claims> getJws(String token) {
return Jwts.parser()
.setSigningKey(generalKey())
.parseClaimsJws(token);
}

/**
* 获取payload body信息
*
* @param token
* @return
*/
public static Claims getClaimsBody(String token) {
try {
return getJws(token).getBody();
}catch (ExpiredJwtException e){
return null;
}
}

/**
* 获取hearder body信息
*
* @param token
* @return
*/
public static JwsHeader getHeaderBody(String token) {
return getJws(token).getHeader();
}

/**
* 是否过期
*
* @param claims
* @return -1:有效,0:有效,1:过期,2:过期
*/
public static int verifyToken(Claims claims) {
if(claims==null){
return 1;
}
try {
claims.getExpiration()
.before(new Date());
// 需要自动刷新TOKEN
if((claims.getExpiration().getTime()-System.currentTimeMillis())>REFRESH_TIME*1000){
return -1;
}else {
return 0;
}
} catch (ExpiredJwtException ex) {
return 1;
}catch (Exception e){
return 2;
}
}

/**
* 由字符串生成加密key
*
* @return
*/
public static SecretKey generalKey() {
byte[] encodedKey = Base64.getEncoder().encode(TOKEN_ENCRY_KEY.getBytes());
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}

public static void main(String[] args) {
/* Map map = new HashMap();
map.put("id","11");*/
System.out.println(AppJwtUtil.getToken(1102L));
Jws<Claims> jws = AppJwtUtil.getJws("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAADWLQQqEMAwA_5KzhURNt_qb1KZYQSi0wi6Lf9942NsMw3zh6AVW2DYmDGl2WabkZgreCaM6VXzhFBfJMcMARTqsxIG9Z888QLui3e3Tup5Pb81013KKmVzJTGo11nf9n8v4nMUaEY73DzTabjmDAAAA.4SuqQ42IGqCgBai6qd4RaVpVxTlZIWC826QA9kLvt9d-yVUw82gU47HDaSfOzgAcloZedYNNpUcd18Ne8vvjQA");
Claims claims = jws.getBody();
System.out.println(claims.get("id"));

}

}