微软OneNote客户预览版学习工具下载(暂未上线):教学好帮手
633
2022-05-30
你好我是辰兮,很高兴你能来阅读,本篇给是初学JWT单点登录后的困惑,现在源码学习后更加了解JWT的结构,小结下来,献给初学者,共同成长,一起进步。
JWT单点登录案例:JWT单点登录代码实现
文章目录
一、JWT的结构
二、JWT源码学习
三、JWT 的特点小结
一、JWT的结构
JWT的结构是什么样的?
token构成包含三个部分:
Header 头部
Payload 负载
Signature 签名
//格式如下 xxx.yyy.zzz
1
2
①JWT-header(头信息)
由两部分组成,令牌类型(即:JWT)、散列算法(HMAC、RSASSA、RSASSA-PSS等)
JWT头部分是一个描述JWT元数据的JSON对象,通常如下所示。
{ "alg": "HS256", "typ": "JWT" }
1
2
3
4
然后,这个JSON被编码为Base64Url,形成JWT的第一部分。
②有效载荷payload
有效载荷部分,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。
JWT的第二部分是payload,其中包含claims。
claims是关于实体(常用的是用户信息)和其他数据的声明
claims有三种类型: registered, public, and private claims。
Registered claims: 这些是一组预定义的claims,非强制性的,但是推荐使用, iss(发行人), exp(到期时间),sub(主题), aud(观众)等;
Public claims: 自定义claims,注意不要和JWT注册表中属性冲突,这里可以查看JWT注册表;
Private claims:这些是自定义的claims,用于在同意使用这些claims的各方之间共享信息,它们既不是Registered claims,也不是Public claims;
{ "sub": "1234567890", "name": "Tom", "admin": true }
1
2
3
4
5
6
请注意,默认情况下JWT是未加密的,任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息,以防止信息泄露。
JSON对象也使用Base64 URL算法转换为字符串保存。
③签名哈希
签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
1
2
3
4
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ. SfcKxwRJSMeKF2QT4fwpMeJf36POkayJV_adQssw6f
1
2
3
4
在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象。
④Base64URL算法
如前所述,JWT头和有效载荷序列化的算法都用到了Base64URL。该算法和常见Base64算法类似,稍有差别。
作为令牌的JWT可以放在URL中
(例如api.example/?token=xxx)
。 Base64中用的三个字符是"+","/“和”=",由于在URL中有特殊含义,因此Base64URL中对他们做了替换:"=“去掉,”+“用”-“替换,”/“用”_"替换,这就是Base64URL算法。
二、JWT源码学习
参考一下常见的代码初学者可能看上去很复杂,接下来分析一波
//登录成功之后,需要生成token String token = Jwts.builder().setSubject("用户名/用户信息") //主题,可以放用户的详细信息 .setIssuedAt(new Date()) //token创建时间 .setExpiration(new Date(System.currentTimeMillis() + 60000)) //token过期时间 .setId("用户ID") //用户ID .setClaims(hashMap) //配置角色信息 .signWith(SignatureAlgorithm.HS256, "WuHan") //加密方式和加密密码 .compact();
1
2
3
4
5
6
7
8
首先Jwts是Java已经被人写好的一个被final修饰的类,然后里面自带很多方法
// // 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是一个接口,里面也自带很多方法,每一个方法的返回值类型是自己本身,这里就是给用户设置相关信息的,所以代码你看上去是连着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");//解析 要和上面“暗号”一样 Jws
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
setSigningKey() 与builder中签名方法signWith()对应,parser中的此方法拥有与signWith()方法相同的三种参数形式,用于设置JWT的签名key,用户后面对JWT进行解析。
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认证很难解释清楚,甚至我都找不到一个合适的中文词语来翻译它。只好用一个比喻来说明。
在实行社保卡之前,我们去医院看病的时候,需要拿着身份证去办理一张就诊卡,办卡的工作人员校验完你的身份证以后,会将你的个人信息录入到卡里面。当你去找医生就诊的时候,医生扫描一下你的就诊卡,就知道了你的所有信息。这个就诊卡就相当于Claims认证中的token,里面的每条信息就是一个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接口中定义了一些变量,我找到了相关图片给你们参考
iss (issuer):签发人 exp (expiration time):过期时间 sub (subject):主题 aud (audience):受众 nbf (Not Before):生效时间 iat (Issued At):签发时间 jti (JWT ID):编号
1
2
3
4
5
6
7
三、JWT 的特点小结
(1)JWT 默认是不加密,但也是可以加密的。生成原始 Token 以后,可以用密钥再加密一次。
(2)JWT 不加密的情况下,不能将秘密数据写入 JWT。
(3)JWT 不仅可以用于认证,也可以用于交换信息。有效使用 JWT,可以降低服务器查询数据库的次数。
(4)JWT 的最大缺点是,由于服务器不保存 session 状态,因此无法在使用过程中废止某个 token,或者更改 token 的权限。也就是说,一旦 JWT 签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑。
(5)JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。为了减少盗用,JWT 的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证。
(6)为了减少盗用,JWT 不应该使用 HTTP 协议明码传输,要使用 HTTPS 协议传输。
The best investment is to invest in yourself
2020.06.04 记录辰兮的第76篇博客
JSON
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。