Jwt
Jwt
JWT是JSON WEB TOKEN的缩写,它是基于 RFC 7519 标准定义的一种可以安全传输的的JSON对象,由于使用了数字签名,所以是可信任和安全的。
组成
header.payload.signature
header中存放签名的生成算法
payload存放附加信息
signature为通过header和payload生成的签名
原理
用户登录后,系统生成token返回给用户。
之后每次调用接口都要在请求中添加Authorization请求头,值为之前的token。
后台系统通过token来对用户认证和授权。
jwt不能防止冒充其他用户
使用
导入坐标
1
2
3
4
5
6
7
8
9
10
11<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!-- 用到SpringSecurity来传用户信息 -->
<!--SpringSecurity依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>添加配置
1
2
3
4
5
6# 自定义jwt key
jwt:
tokenHeader: Authorization #JWT存储的请求头
secret: mySecret #JWT加解密使用的密钥
expiration: 604800 #JWT的超期限时间(60*60*24)
tokenHead: Bearer #JWT负载中拿到开头编写工具类(结合Spring Security)
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
102package com.xw.mallLearning.utils;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* token工具类
* 获取token、校验token、刷新token过期时间
*/
@Slf4j
@Component
public class JwtTokenUtil {
private static final String CLAIM_KEY_USERNAME = "sub";
private static final String CLAIM_KEY_CREATED = "created";
@Value("${jwt.secret}")
private String secret; // 加密秘钥
@Value("${jwt.expiration}")
private Long expiration; // token保留时间
// 获取token中的用户名
public String getUserNameFormToken(String token) {
String username;
try {
Claims claims = getClaimsFormToken(token);
username = claims.getSubject();
} catch (Exception e) {
return null;
}
return username;
}
// 验证token是否有效
public boolean validateToken(String token, UserDetails userDetails) {
String username = getUserNameFormToken(token);
return userDetails.getUsername().equals(username) && isTokenExpired(token);
}
// 生成Token
public String generateToken(UserDetails userDetails) {
HashMap<String, Object> claims = new HashMap<>();
claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
claims.put(CLAIM_KEY_CREATED, new Date());
return generateTokenFromClaims(claims);
}
// 刷新token
public String refreshToken(String token) {
Claims claims = getClaimsFormToken(token);
claims.put(CLAIM_KEY_CREATED, new Date());
return generateTokenFromClaims(claims);
}
// 验证token是否实效
private boolean isTokenExpired(String token) {
Date expireDate = getExpireDateFormToken(token);
return expireDate.before(new Date());
}
// 获取Token过期时间
private Date getExpireDateFormToken(String token) {
Claims claims = getClaimsFormToken(token);
return claims.getExpiration();
}
// 根据负载信息生成Token
private String generateTokenFromClaims(Map<String, Object> claims) {
return Jwts.builder()
.setClaims(claims) // 设置token中负载信息
.setExpiration(generateExpirationDate()) // 设置超时时间
.signWith(SignatureAlgorithm.ES512, secret) // 设置加密方式
.compact();
}
// 生成Token过期时间
private Date generateExpirationDate() {
return new Date(System.currentTimeMillis() + expiration * 1000);
}
// 获取token中的JWT负载
private Claims getClaimsFormToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
} catch (Exception e) {
log.info("JWT验证失败:{}", token);
}
return claims;
}
}编写工具类(不是用其他框架)
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
125package com.xw.place.utils;
import io.jsonwebtoken.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.UUID;
/**
* token工具类
* 获取token、校验token、刷新token过期时间
*/
@Slf4j
@Component
public class JwtTokenUtil {
@Value("${jwt.secret}")
private static String SECRET; // 加密秘钥
@Value("${jwt.expiration}")
private static Long EXPIRATION; // token保留时间(s)
@Value("${jwt.refresh_time}")
private static Integer REFRESH_TIME;
/**
* 生成token
* @param id
* @return
*/
public static String getToken(Long id) {
HashMap<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") // 说明
.setAudience("app") // 接收用户
.compressWith(CompressionCodecs.GZIP) // 数据压缩方式
.signWith(SignatureAlgorithm.HS512, generalKey()) // 数据压缩方式
.setExpiration(new Date(currentTime + EXPIRATION * 1000)) // 过期时间戳
.addClaims(claimMaps) // 载荷信息
.compact();
}
/**
* 生成加密key
* @return
*/
public static SecretKey generalKey() {
byte[] encodedKey = Base64.getEncoder().encode(SECRET.getBytes());
SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
return key;
}
/**
* 获取payload body信息
*
* @param token
* @return
*/
public static Claims getClaimsBody(String token) {
try {
return getJws(token).getBody();
} catch (Exception e) {
return null;
}
}
/**
* 获取headers body信息
* @param token
* @return
*/
public static JwsHeader getHeaderBody(String token) {
return getJws(token).getHeader();
}
/**
* 判断token是否过期
* @param claims
* @return -1 有效,0 有效,1:过期,2 过期
*/
public static int verifyToken(Claims claims) {
if (claims == null) {
return 1;
}
try {
claims.getExpiration()
.before(new Date());
if ((claims.getExpiration().getTime() - System.currentTimeMillis()) > REFRESH_TIME * 1000) {
return -1;
} else {
return 0;
}
} catch (ExpiredJwtException ex) {
return 1;
} catch (Exception e) {
return 2;
}
}
// 获取载荷信息
private static Jws<Claims> getJws(String token) {
return Jwts.parser()
.setSigningKey(generalKey())
.parseClaimsJws(token);
}
// 测试
public static void main(String[] args) {
System.out.println(JwtTokenUtil.getToken(1102L));
Jws<Claims> jws = JwtTokenUtil.getJws("eyJhbGciOiJIUzUxMiIsInppcCI6IkdaSVAifQ.H4sIAAAAAAAAAB2LUQrEIAwF75JvBROjYm-jVcGFBUELW0rv3nT_3jDzLvisDhtwKxzCbrRr6DQ3izqVitpzzL5FyqYgKOhpwYY-UkDHziuYR5b3POeqX_HpKIJpDNn1N_6ttWTobbs4REP3Az_PtEl1AAAA.Mrst1ZCLW7ItSxLl26TiYbpN-7XPNn1HUuP0ZyGqNZgLitUlt3Vqfnu9MGI1blugwdI6wBriAmydZITaYuRRmA");
Claims claims = jws.getBody();
System.out.println(claims.get("id"));
}
}
Jwt
http://xwww12.github.io/2023/02/06/其他/Jwt/