前言
說(shuō)說(shuō)JWT,先說(shuō)下互聯(lián)網(wǎng)服務(wù)常見(jiàn)的兩種用戶(hù)認(rèn)證方式:
session認(rèn)證與Token認(rèn)證
session認(rèn)證
傳統(tǒng)的Session認(rèn)證的大體流程可以表示為用戶(hù)提供用戶(hù)名和密碼登錄后由服務(wù)器存儲(chǔ)一份用戶(hù)登錄信息并傳遞給瀏覽器保存為Cookie,并在下次請(qǐng)求中根據(jù)Cookie來(lái)識(shí)別用戶(hù),但這種方式缺陷明顯:
- Session都是保存在內(nèi)存中,隨著認(rèn)證用戶(hù)的增多,服務(wù)端的開(kāi)銷(xiāo)明顯增大
- 保存在內(nèi)存中的Session限制了分布式的應(yīng)用
- Cookie容易被截獲偽造
Token認(rèn)證
Token 泛指身份驗(yàn)證時(shí)使用的令牌,Token鑒權(quán)機(jī)制從某些角度而言與Cookie是一個(gè)作用,其目的是讓后臺(tái)知道請(qǐng)求是來(lái)自于受信的客戶(hù)端,其通過(guò)實(shí)現(xiàn)了某種算法加密的Token字符串來(lái)完成鑒權(quán)工作,其優(yōu)點(diǎn)在于:
- 服務(wù)器不需要保存 Session 數(shù)據(jù)(無(wú)狀態(tài)),容易實(shí)現(xiàn)擴(kuò)展
- 有效避免Cookie被截獲引發(fā)的CSRF攻擊
- 可以存儲(chǔ)一些業(yè)務(wù)邏輯所必要的非敏感信息
- 便于傳輸,其構(gòu)成非常簡(jiǎn)單,字節(jié)占用小
JWT簡(jiǎn)介
JWT定義
JWT全稱(chēng)為Json web token,也就是 Json 格式的 web token,可以這么理解:
Token // 個(gè)人證件
JWT // 個(gè)人身份證
JWT數(shù)據(jù)結(jié)構(gòu)
JWT由三段字符串組成,中間用.分隔,如下:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsInNjb3BlIjo4LCJleHAiOjE3MTU3NDAyMjIsImlhdCI6MTYyOTM0MDIyMn0.wuRsF5wvLHbDF_21Pocas8SeXQ315rgBl6wm1LRL2bQ
JWT 的三個(gè)部分依次如下:
- Header(頭部)// Header 部分是一個(gè) JSON 對(duì)象,描述 JWT 的元數(shù)據(jù),通常是下面的樣子。
- Payload(負(fù)載)// Payload 部分是一個(gè) JSON 對(duì)象,用來(lái)存放實(shí)際需要傳遞的數(shù)據(jù)
- Signature(簽名)// Signature 部分是對(duì)前兩部分的簽名,防止數(shù)據(jù)篡改
第一段字符串Header:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
將其 Base64 解碼后得到:
1
2
3
4
|
{ "typ" : "JWT" , // TOKEN TYPE ,token類(lèi)型 "alg" : "HS256" //ALGORITHM,算法 哈希256 } |
第二段字符串Payload:eyJ1aWQiOjEsInNjb3BlIjo4LCJleHAiOjE3MTU3NDAyMjIsImlhdCI6MTYyOTM0MDIyMn0
PAYLOAD是數(shù)據(jù)載體,可以有自定義數(shù)據(jù)
1
2
3
|
{ "uid" : "1234567890" // 自定義數(shù)據(jù) } |
第三段字符串Signature:wuRsF5wvLHbDF_21Pocas8SeXQ315rgBl6wm1LRL2bQ
Signature 部分是對(duì)前兩部分的簽名,防止數(shù)據(jù)篡改。
JWT的類(lèi)庫(kù)
Java 中的 JWT 有很多類(lèi)庫(kù),關(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 # 過(guò)期時(shí)間 token-expired-in: 86400000 |
JWT工具類(lèi)
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工具類(lèi) * @author coisini * @date Aug 18, 2021 * @Version 1.0 */ @Component public class JwtUtil { /** * key */ private static String jwtKey; /** * 過(guò)期時(shí)間 */ private static Integer expiredTimeIn; /** * JWT KEY * @param jwtKey */ @Value ( "${coisini.security.jwt-key}" ) public void setJwtKey(String jwtKey) { JwtUtil.jwtKey = jwtKey; } /** * 過(guò)期時(shí)間 * @param expiredTimeIn */ @Value ( "${coisini.security.token-expired-in}" ) public void setExpiredTimeIn(Integer expiredTimeIn) { JwtUtil.expiredTimeIn = expiredTimeIn; } /** * 生成令牌 * @param uid 用戶(hù)id * @return */ public static String makeToken(Long uid) { return JwtUtil.getToken(uid); } /** * 獲取令牌 * @param uid 用戶(hù)id * @param scope 權(quán)限分級(jí)數(shù)字 * @return */ private static String getToken(Long uid) { // 指定算法 Algorithm algorithm = Algorithm.HMAC256(JwtUtil.jwtKey); Map<String, Date> dateMap = JwtUtil.calculateExpiredIssues(); /** * withClaim() 寫(xiě)入自定義數(shù)據(jù) * withExpiresAt() 設(shè)置過(guò)期時(shí)間 * withIssuedAt() 設(shè)置當(dāng)前時(shí)間 * 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()); } /** * 驗(yàn)證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 ; } /** * 計(jì)算過(guò)期時(shí)間 * @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)前時(shí)間 map.put( "now" , now); // 過(guò)期時(shí)間 map.put( "expiredTime" , calendar.getTime()); return map; } } |
測(cè)試接口
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); } /** * 驗(yàn)證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; } } |
測(cè)試結(jié)果
JWT生成的Token應(yīng)該放在請(qǐng)求頭內(nèi)來(lái)傳輸,后端統(tǒng)一攔截驗(yàn)證,這里留在下篇文章吧。。。
到此這篇關(guān)于SpringBoot集成Auth0 JWT的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot集成Auth0 JWT內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://www.cnblogs.com/maggieq8324/p/15161692.html