學(xué)習(xí)筆記20170601">【PMP】學(xué)習(xí)筆記20170601
710
2022-05-30
你好我是辰兮,很高興你能來(lái)閱讀,本篇給是初學(xué)JWT單點(diǎn)登錄后的困惑,現(xiàn)在源碼學(xué)習(xí)后更加了解JWT的結(jié)構(gòu),小結(jié)下來(lái),獻(xiàn)給初學(xué)者,共同成長(zhǎng),一起進(jìn)步。
JWT單點(diǎn)登錄案例:JWT單點(diǎn)登錄代碼實(shí)現(xiàn)
文章目錄
一、JWT的結(jié)構(gòu)
二、JWT源碼學(xué)習(xí)
三、JWT 的特點(diǎn)小結(jié)
一、JWT的結(jié)構(gòu)
JWT的結(jié)構(gòu)是什么樣的?
token構(gòu)成包含三個(gè)部分:
Header 頭部
Payload 負(fù)載
Signature 簽名
//格式如下 xxx.yyy.zzz
1
2
①JWT-header(頭信息)
由兩部分組成,令牌類(lèi)型(即:JWT)、散列算法(HMAC、RSASSA、RSASSA-PSS等)
JWT頭部分是一個(gè)描述JWT元數(shù)據(jù)的JSON對(duì)象,通常如下所示。
{ "alg": "HS256", "typ": "JWT" }
1
2
3
4
然后,這個(gè)JSON被編碼為Base64Url,形成JWT的第一部分。
②有效載荷payload
有效載荷部分,是JWT的主體內(nèi)容部分,也是一個(gè)JSON對(duì)象,包含需要傳遞的數(shù)據(jù)。
JWT的第二部分是payload,其中包含claims。
claims是關(guān)于實(shí)體(常用的是用戶信息)和其他數(shù)據(jù)的聲明
claims有三種類(lèi)型: registered, public, and private claims。
Registered claims: 這些是一組預(yù)定義的claims,非強(qiáng)制性的,但是推薦使用, iss(發(fā)行人), exp(到期時(shí)間),sub(主題), aud(觀眾)等;
Public claims: 自定義claims,注意不要和JWT注冊(cè)表中屬性沖突,這里可以查看JWT注冊(cè)表;
Private claims:這些是自定義的claims,用于在同意使用這些claims的各方之間共享信息,它們既不是Registered claims,也不是Public claims;
{ "sub": "1234567890", "name": "Tom", "admin": true }
1
2
3
4
5
6
請(qǐng)注意,默認(rèn)情況下JWT是未加密的,任何人都可以解讀其內(nèi)容,因此不要構(gòu)建隱私信息字段,存放保密信息,以防止信息泄露。
JSON對(duì)象也使用Base64 URL算法轉(zhuǎn)換為字符串保存。
③簽名哈希
簽名哈希部分是對(duì)上面兩部分?jǐn)?shù)據(jù)簽名,通過(guò)指定的算法生成哈希,以確保數(shù)據(jù)不會(huì)被篡改。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
1
2
3
4
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ. SfcKxwRJSMeKF2QT4fwpMeJf36POkayJV_adQssw6f
1
2
3
4
在計(jì)算出簽名哈希后,JWT頭,有效載荷和簽名哈希的三個(gè)部分組合成一個(gè)字符串,每個(gè)部分用"."分隔,就構(gòu)成整個(gè)JWT對(duì)象。
④Base64URL算法
如前所述,JWT頭和有效載荷序列化的算法都用到了Base64URL。該算法和常見(jiàn)Base64算法類(lèi)似,稍有差別。
作為令牌的JWT可以放在URL中
(例如api.example/?token=xxx)
。 Base64中用的三個(gè)字符是"+","/“和”=",由于在URL中有特殊含義,因此Base64URL中對(duì)他們做了替換:"=“去掉,”+“用”-“替換,”/“用”_"替換,這就是Base64URL算法。
二、JWT源碼學(xué)習(xí)
參考一下常見(jiàn)的代碼初學(xué)者可能看上去很復(fù)雜,接下來(lái)分析一波
//登錄成功之后,需要生成token String token = Jwts.builder().setSubject("用戶名/用戶信息") //主題,可以放用戶的詳細(xì)信息 .setIssuedAt(new Date()) //token創(chuàng)建時(shí)間 .setExpiration(new Date(System.currentTimeMillis() + 60000)) //token過(guò)期時(shí)間 .setId("用戶ID") //用戶ID .setClaims(hashMap) //配置角色信息 .signWith(SignatureAlgorithm.HS256, "WuHan") //加密方式和加密密碼 .compact();
1
2
3
4
5
6
7
8
首先Jwts是Java已經(jīng)被人寫(xiě)好的一個(gè)被final修飾的類(lèi),然后里面自帶很多方法
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package io.jsonwebtoken; import io.jsonwebtoken.impl.DefaultClaims; import io.jsonwebtoken.impl.DefaultHeader; import io.jsonwebtoken.impl.DefaultJwsHeader; import io.jsonwebtoken.impl.DefaultJwtBuilder; import io.jsonwebtoken.impl.DefaultJwtParser; import java.util.Map; public final class Jwts { private Jwts() { } public static Header header() { return new DefaultHeader(); } public static Header header(Map
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
JwtBuilder是一個(gè)接口,里面也自帶很多方法,每一個(gè)方法的返回值類(lèi)型是自己本身,這里就是給用戶設(shè)置相關(guān)信息的,所以代碼你看上去是連著set的。
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package io.jsonwebtoken; import java.security.Key; import java.util.Date; import java.util.Map; public interface JwtBuilder extends ClaimsMutator
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
JWT的解析
try { JwtParser parser = Jwts.parser(); parser.setSigningKey("WuHan");//解析 要和上面“暗號(hào)”一樣 Jws
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
setSigningKey() 與builder中簽名方法signWith()對(duì)應(yīng),parser中的此方法擁有與signWith()方法相同的三種參數(shù)形式,用于設(shè)置JWT的簽名key,用戶后面對(duì)JWT進(jìn)行解析。
package io.jsonwebtoken; import java.security.Key; import java.util.Date; public interface JwtParser { char SEPARATOR_CHAR = '.'; JwtParser requireId(String var1); JwtParser requireSubject(String var1); JwtParser requireAudience(String var1); JwtParser requireIssuer(String var1); JwtParser requireIssuedAt(Date var1); JwtParser requireExpiration(Date var1); JwtParser requireNotBefore(Date var1); JwtParser require(String var1, Object var2); JwtParser setClock(Clock var1); JwtParser setAllowedClockSkewSeconds(long var1); JwtParser setSigningKey(byte[] var1); JwtParser setSigningKey(String var1); JwtParser setSigningKey(Key var1); JwtParser setSigningKeyResolver(SigningKeyResolver var1); JwtParser setCompressionCodecResolver(CompressionCodecResolver var1); boolean isSigned(String var1); Jwt parse(String var1) throws ExpiredJwtException, MalformedJwtException, SignatureException, IllegalArgumentException;
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
Claims認(rèn)證很難解釋清楚,甚至我都找不到一個(gè)合適的中文詞語(yǔ)來(lái)翻譯它。只好用一個(gè)比喻來(lái)說(shuō)明。
在實(shí)行社保卡之前,我們?nèi)メt(yī)院看病的時(shí)候,需要拿著身份證去辦理一張就診卡,辦卡的工作人員校驗(yàn)完你的身份證以后,會(huì)將你的個(gè)人信息錄入到卡里面。當(dāng)你去找醫(yī)生就診的時(shí)候,醫(yī)生掃描一下你的就診卡,就知道了你的所有信息。這個(gè)就診卡就相當(dāng)于Claims認(rèn)證中的token,里面的每條信息就是一個(gè)Claim.
package io.jsonwebtoken; import java.util.Date; import java.util.Map; public interface Claims extends Map
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
上述Claims接口中定義了一些變量,我找到了相關(guān)圖片給你們參考
iss (issuer):簽發(fā)人 exp (expiration time):過(guò)期時(shí)間 sub (subject):主題 aud (audience):受眾 nbf (Not Before):生效時(shí)間 iat (Issued At):簽發(fā)時(shí)間 jti (JWT ID):編號(hào)
1
2
3
4
5
6
7
三、JWT 的特點(diǎn)小結(jié)
(1)JWT 默認(rèn)是不加密,但也是可以加密的。生成原始 Token 以后,可以用密鑰再加密一次。
(2)JWT 不加密的情況下,不能將秘密數(shù)據(jù)寫(xiě)入 JWT。
(3)JWT 不僅可以用于認(rèn)證,也可以用于交換信息。有效使用 JWT,可以降低服務(wù)器查詢(xún)數(shù)據(jù)庫(kù)的次數(shù)。
(4)JWT 的最大缺點(diǎn)是,由于服務(wù)器不保存 session 狀態(tài),因此無(wú)法在使用過(guò)程中廢止某個(gè) token,或者更改 token 的權(quán)限。也就是說(shuō),一旦 JWT 簽發(fā)了,在到期之前就會(huì)始終有效,除非服務(wù)器部署額外的邏輯。
(5)JWT 本身包含了認(rèn)證信息,一旦泄露,任何人都可以獲得該令牌的所有權(quán)限。為了減少盜用,JWT 的有效期應(yīng)該設(shè)置得比較短。對(duì)于一些比較重要的權(quán)限,使用時(shí)應(yīng)該再次對(duì)用戶進(jìn)行認(rèn)證。
(6)為了減少盜用,JWT 不應(yīng)該使用 HTTP 協(xié)議明碼傳輸,要使用 HTTPS 協(xié)議傳輸。
The best investment is to invest in yourself
2020.06.04 記錄辰兮的第76篇博客
JSON
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。