概念

JWT结构

JWT由三段信息构成,通过 .链接在一起构成jwt字符串

  1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

JWT三部分介绍:

header

jwt的头部承载两部分信息:

  • 声明token类型,这里是jwt
  • 声明token的加密方式 通常使用 HMAC SHA256等

完整的头部如下:

  1. {
  2. 'typ': 'JWT',
  3. 'alg': 'HS256'
  4. }

通过对该json字符串进行BASE64压缩就得到了header部分

  1. eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

Payload

有关实体的声明,存放有效信息的地方,这些有效信息包含三个部分
声明有三种类型: registered, public private

  • Registered claims : 这里有一组预定义的声明,它们不是强制的,但是推荐。比如:iss (issuer), exp (expiration time), sub (subject), aud (audience)等。

标准中注册的声明 (建议但不强制使用) :

iss jwt签发者
sub jwt所面向的用户
aud 接收jwt的一方
exp jwt的过期时间,这个过期时间必须要大于签发时间
nbf 定义在什么时间之前,该jwt都是不可用的.
iat jwt的签发时间
jti jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
  • Public claims : 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
  • Private claims : 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

[

](https://blog.csdn.net/qq_32609199/article/details/109569396)

  1. {
  2. "uid": "1234567890",
  3. "name": "John Doe",
  4. "admin": true
  5. }

对该json字符串进行BASE64压缩就得到了第二部分。从这里可以看出payload完全是明文暴露的,请不要放置一些重要信息

  1. eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

Signature

jwt的第三部分是一个签证信息,以token的前两部分作为明文,用共同协商好的秘钥进行签名(对称签名和非对称签名)。
这个签证信息由三部分组成:

  • header (base64后的)
  • payload (base64后的)
  • secret

签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。
通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

  1. encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
  2. signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

简单应用

加密

  1. package com.jili.jwt;
  2. import io.jsonwebtoken.JwtBuilder;
  3. import io.jsonwebtoken.Jwts;
  4. import io.jsonwebtoken.SignatureAlgorithm;
  5. import java.util.Date;
  6. import java.util.UUID;
  7. /**
  8. * @author: Jili
  9. * @date: Created on 2021/6/24 15:01
  10. */
  11. public class Test {
  12. private long time = 1000*60*60*24;
  13. private String signature = "admin";
  14. @org.junit.jupiter.api.Test
  15. public void jwt(){
  16. JwtBuilder jwtBuilder= Jwts.builder();
  17. String jwtToken = jwtBuilder
  18. //Header
  19. .setHeaderParam("typ","JWT")
  20. .setHeaderParam("alg","HS256")
  21. //payload
  22. .claim("username","jili")
  23. .claim("role","admin")
  24. //payload sub主题
  25. .setSubject("admin-test")
  26. //payload 有效时间
  27. .setExpiration(new Date(System.currentTimeMillis()+time))
  28. .setId(UUID.randomUUID().toString())
  29. //signature
  30. .signWith(SignatureAlgorithm.HS256,signature)
  31. //拼接
  32. .compact();
  33. System.out.println(jwtToken);
  34. }
  35. }

输出的JWT为:

  1. eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImppbGkiLCJyb2xlIjoiYWRtaW4iLCJzdWIiOiJhZG1pbi10ZXN0IiwiZXhwIjoxNjI0NjA4MDM5LCJqdGkiOiJjOGJlODQ2NS1jNTg4LTRjOGEtYWI4OS04OGVjNDg5NGMwN2UifQ.q5s0S0YINhrAz2Yo1bHsWDNLQEiiMkYak_mC76C2rx4

解密

  1. public void parse(){
  2. String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6ImppbGkiLCJyb2xlIjoiYWRtaW4iLCJzdWIiOiJhZG1pbi10ZXN0IiwiZXhwIjoxNjI0NjA4MDM5LCJqdGkiOiJjOGJlODQ2NS1jNTg4LTRjOGEtYWI4OS04OGVjNDg5NGMwN2UifQ.q5s0S0YINhrAz2Yo1bHsWDNLQEiiMkYak_mC76C2rx4";
  3. JwtParser jwtParser = Jwts.parser();
  4. //签名
  5. Jws<Claims> claimsJws = jwtParser.setSigningKey(signature).parseClaimsJws(token);
  6. jwtParser.setSigningKey(signature).parseClaimsJws(token);
  7. Claims claims = claimsJws.getBody();
  8. System.out.println(claims.get("username"));
  9. System.out.println(claims.get("role"));
  10. System.out.println(claims.getExpiration());
  11. }

输出:

  1. jili
  2. admin
  3. Fri Jun 25 16:00:39 CST 2021