前言
說說JWT,先說下互聯(lián)網(wǎng)服務(wù)常見的兩種用戶認(rèn)證方式:
session認(rèn)證與Token認(rèn)證
session認(rèn)證
傳統(tǒng)的Session認(rèn)證的大體流程可以表示為用戶提供用戶名和密碼登錄后由服務(wù)器存儲一份用戶登錄信息并傳遞給瀏覽器保存為Cookie,并在下次請求中根據(jù)Cookie來識別用戶,但這種方式缺陷明顯:
- Session都是保存在內(nèi)存中,隨著認(rèn)證用戶的增多,服務(wù)端的開銷明顯增大
- 保存在內(nèi)存中的Session限制了分布式的應(yīng)用
- Cookie容易被截獲偽造
Token認(rèn)證
Token 泛指身份驗證時使用的令牌,Token鑒權(quán)機(jī)制從某些角度而言與Cookie是一個作用,其目的是讓后臺知道請求是來自于受信的客戶端,其通過實(shí)現(xiàn)了某種算法加密的Token字符串來完成鑒權(quán)工作,其優(yōu)點(diǎn)在于:
- 服務(wù)器不需要保存 Session 數(shù)據(jù)(無狀態(tài)),容易實(shí)現(xiàn)擴(kuò)展
- 有效避免Cookie被截獲引發(fā)的CSRF攻擊
- 可以存儲一些業(yè)務(wù)邏輯所必要的非敏感信息
- 便于傳輸,其構(gòu)成非常簡單,字節(jié)占用小
JWT簡介
JWT定義
JWT全稱為Json web token,也就是 Json 格式的 web token,可以這么理解:
Token // 個人證件
JWT // 個人身份證
JWT數(shù)據(jù)結(jié)構(gòu)
JWT由三段字符串組成,中間用.分隔,如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsInNjb3BlIjo4LCJleHAiOjE3MTU3NDAyMjIsImlhdCI6MTYyOTM0MDIyMn0.wuRsF5wvLHbDF_21Pocas8SeXQ315rgBl6wm1LRL2bQ
JWT 的三個部分依次如下:
- Header(頭部)// Header 部分是一個 JSON 對象,描述 JWT 的元數(shù)據(jù),通常是下面的樣子。
- Payload(負(fù)載)// Payload 部分是一個 JSON 對象,用來存放實(shí)際需要傳遞的數(shù)據(jù)
- Signature(簽名)// Signature 部分是對前兩部分的簽名,防止數(shù)據(jù)篡改
第一段字符串Header:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
將其 Base64 解碼后得到:
1
2
3
4
|
{ "typ" : "JWT" , // TOKEN TYPE ,token類型 "alg" : "HS256" //ALGORITHM,算法 哈希256 } |
第二段字符串Payload:eyJ1aWQiOjEsInNjb3BlIjo4LCJleHAiOjE3MTU3NDAyMjIsImlhdCI6MTYyOTM0MDIyMn0
PAYLOAD是數(shù)據(jù)載體,可以有自定義數(shù)據(jù)
1
2
3
|
{ "uid" : "1234567890" // 自定義數(shù)據(jù) } |
第三段字符串Signature:wuRsF5wvLHbDF_21Pocas8SeXQ315rgBl6wm1LRL2bQ
Signature 部分是對前兩部分的簽名,防止數(shù)據(jù)篡改。
JWT的類庫
Java 中的 JWT 有很多類庫,關(guān)于其優(yōu)缺點(diǎn)可以在官網(wǎng)查看:https://jwt.io/,這里我們介紹Auth0的JWT的集成使用方式
Auth0 實(shí)現(xiàn)的 com.auth0 / java-jwt / 3.3.0
Brian Campbell 實(shí)現(xiàn)的 org.bitbucket.b_c / jose4j / 0.6.3
connect2id 實(shí)現(xiàn)的 com.nimbusds / nimbus-jose-jwt / 5.7
Les Hazlewood 實(shí)現(xiàn)的 io.jsonwebtoken / jjwt / 0.9.0
FusionAuth 實(shí)現(xiàn)的 io.fusionauth / fusionauth-jwt / 3.1.0
Vert.x 實(shí)現(xiàn)的 io.vertx / vertx-auth-jwt / 3.5.1
具體實(shí)現(xiàn)
JWT配置
pom.xml
1
2
3
4
5
6
|
<!-- jwt --> < dependency > < groupId >com.auth0</ groupId > < artifactId >java-jwt</ artifactId > < version >3.8.1</ version > </ dependency > |
application.yml
1
2
3
4
5
|
coisini: security: jwt-key: coisini # 過期時間 token-expired-in: 86400000 |
JWT工具類
JwtUtil.java
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
|
import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.exceptions.JWTVerificationException; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.*; /** * @Description JWT工具類 * @author coisini * @date Aug 18, 2021 * @Version 1.0 */ @Component public class JwtUtil { /** * key */ private static String jwtKey; /** * 過期時間 */ private static Integer expiredTimeIn; /** * JWT KEY * @param jwtKey */ @Value ( "${coisini.security.jwt-key}" ) public void setJwtKey(String jwtKey) { JwtUtil.jwtKey = jwtKey; } /** * 過期時間 * @param expiredTimeIn */ @Value ( "${coisini.security.token-expired-in}" ) public void setExpiredTimeIn(Integer expiredTimeIn) { JwtUtil.expiredTimeIn = expiredTimeIn; } /** * 生成令牌 * @param uid 用戶id * @return */ public static String makeToken(Long uid) { return JwtUtil.getToken(uid); } /** * 獲取令牌 * @param uid 用戶id * @param scope 權(quán)限分級數(shù)字 * @return */ private static String getToken(Long uid) { // 指定算法 Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey); Map<String, Date> dateMap = JwtUtil.calculateExpiredIssues(); /** * withClaim() 寫入自定義數(shù)據(jù) * withExpiresAt() 設(shè)置過期時間 * withIssuedAt() 設(shè)置當(dāng)前時間 * sign() 簽名算法 */ return JWT.create() .withClaim( "uid" , uid) .withExpiresAt(dateMap.get( "expiredTime" )) .withIssuedAt(dateMap.get( "now" )) .sign(algorithm); } /** * 獲取自定義數(shù)據(jù) * @param token * @return */ public static Optional<Map<String, Claim>> getClaims(String token) { DecodedJWT decodedJWT; // 指定算法 Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey); JWTVerifier jwtVerifier = JWT.require(algorithm).build(); try { decodedJWT = jwtVerifier.verify(token); } catch (JWTVerificationException e) { return Optional.empty(); } return Optional.of(decodedJWT.getClaims()); } /** * 驗證Token * @param token * @return */ public static boolean verifyToken(String token) { try { Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey); JWTVerifier jwtVerifier = JWT.require(algorithm).build(); jwtVerifier.verify(token); } catch (JWTVerificationException e) { return false ; } return true ; } /** * 計算過期時間 * @return */ private static Map<String, Date> calculateExpiredIssues() { Map<String, Date> map = new HashMap<>(); Calendar calendar = Calendar.getInstance(); Date now = calendar.getTime(); calendar.add(Calendar.SECOND, JwtUtil.expiredTimeIn); // 當(dāng)前時間 map.put( "now" , now); // 過期時間 map.put( "expiredTime" , calendar.getTime()); return map; } } |
測試接口
JwtController.java
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
|
@RestController @RequestMapping ( "/jwt" ) public class JwtController { /** * 獲取Token * @param id * @return */ @GetMapping (value = "/get" ) public String getToken( @RequestParam Long id) { return JwtUtil.makeToken(id); } /** * 驗證Token * @param token * @return */ @PostMapping ( "/verify" ) public Map<String, Boolean> verify( @RequestParam String token) { Map<String, Boolean> map = new HashMap<>(); Boolean valid = JwtUtil.verifyToken(token); map.put( "is_valid" , valid); return map; } } |
測試結(jié)果
JWT生成的Token應(yīng)該放在請求頭內(nèi)來傳輸,后端統(tǒng)一攔截驗證,這里留在下篇文章吧。。。
到此這篇關(guān)于SpringBoot集成Auth0 JWT的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot集成Auth0 JWT內(nèi)容請搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://www.cnblogs.com/maggieq8324/p/15161692.html