本文最后更新于:May 13, 2023 pm
                
              
            
            
              JSON Web 令牌是一种开放的行业标准 RFC 7519方法,用于在两方之间安全地表示声明。JSON Web Token (JWT) 是一个开放标准 ( RFC 7519 ),它定义了一种紧凑且自包含的方式,用于在各方之间以 JSON 对象的形式安全传输信息。此信息可以验证和信任,因为它是数字签名的。JWT 可以使用密钥(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对进行签名。官网
目录

JWT结构
令牌组成
- 标头(Header)
 
 
- 有效载荷(Payload)
 
 
- 签名(Signature)
 
 
JWT通常形式为:xxxx.yyyy.zzzz,对应Header.Payload.Signature。
注意:Base64是一种编码,而不是加密。Base64编码是可以被还原的。(可逆的)
标头由两部分组成:令牌的类型(即JWT)和所使用的签名算法。例如:HMACSHA256(HS256) 或RSA。还会进行Base64编码,进而组成JWT的第一部分。
 | {   "alg": "HS256",   "typ": "JWT" }
 
  | 
 
上述是简写了的:alg(Algorithm)、typ(type)。
Payload
有效负载,其中包含声明。声明有关实体(通常为用户)和其他数据的声明(简单说就是用户信息,但不要放用户的敏感信息!)。也是进行Base64编码,进而组成JWT的第二部分。
 | {   "id": "123456",   "name": "loong",   "role": "admin" }
 
  | 
 
Signature
前两者(Header、Payload)用Base64编码后,再进行Header中指定的算法(本例中是 HS256)进行签名,最后组成Signature(不要忘记点号(.))。最后组成JWT的第三部分。
 | HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret); 
 
  | 
 
参考
如果一个令牌为:xxx.yyy.zzz,那么,
所以,如果 T = xxx+yyy ,那么:
- T = base64UrlEncode(header).base64UrlEncode(payload)
 
如果,zzz = T + 签名,那么:
zzz = T + 签名;
 
zzz = HMACSHA256(T,secret);
 
zzz = HMACSHA256(base64UrlEncode(header)+”.”+base64UrlEncode(payload),secret)
 
所以,最后的结果为:
 | base64UrlEncode(header). base64UrlEncode(payload). HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)
 
  | 
 
生成Token
导入依赖
这里以java-jwt为例:
 | <dependency>     <groupId>com.auth0</groupId>     <artifactId>java-jwt</artifactId>     <version>3.18.3</version> </dependency>
 
  | 
 
 | payload官方定义包含属性如下(非强制): iss: jwt签发者 sub: jwt所面向的用户 aud: 接收jwt的一方 exp: jwt的过期时间,这个过期时间必须要大于签发时间 nbf: 定义在什么时间之前,该jwt都是不可用的. iat: jwt的签发时间 jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
 
  | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
   | @Test void contextLoads() {     Algorithm alg = Algorithm.HMAC256("sdfwefe");      Map<String,Object> header = new HashMap<>();      Calendar ins = Calendar.getInstance();     ins.add(Calendar.SECOND,60); 
      String token = JWT.create()                  .withHeader(header)          .withIssuedAt(new Date())                   .withClaim("userid",23)         .withClaim("username","loong")         .withExpiresAt(ins.getTime())                   .sign(alg);
      System.out.println(token); }
 
  | 
 
放置的位置有一定的限制!签名放最后,不能在签名后再加其他的。
验证Token
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
   | @Test void contextLoads2() {     Algorithm alg = Algorithm.HMAC256("sdfwefe");      JWTVerifier jwtVerifier = JWT.require(alg).build();          String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDM5NDk0MzAsImlhdCI6MTY0Mzk0OTM3MCwidXNlcmlkIjoyMywidXNlcm5hbWUiOiJsb29uZyJ9.s2rvfcW5wSvEtCDP0189Sxh7LItbWZKMG2xZ4-Rb220";     DecodedJWT jwt = jwtVerifier.verify(token); 
           String decodeHeader = StringUtils.newStringUtf8(Base64.decodeBase64(jwt.getHeader()));          String decodePayload = StringUtils.newStringUtf8(Base64.decodeBase64(jwt.getPayload()));          String signature = jwt.getSignature();
           int userid = jwt.getClaim("userid").asInt();     String username = jwt.getClaim("username").asString();
      System.out.println("header:" + jwt.getHeader());     System.out.println("payload:" + jwt.getPayload());     System.out.println("signature:" + signature);
      System.out.println("headerString:" + decodeHeader);     System.out.println("payloadString:" + decodePayload);
      System.out.println("nameid:" + userid);     System.out.println("username:" + username);
      System.out.println("过期时间为: "+ jwt.getExpiresAt()); }
 
  | 
 
输出:
 | header:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 payload:eyJleHAiOjE2NDM5NDk0MzAsImlhdCI6MTY0Mzk0OTM3MCwidXNlcmlkIjoyMywidXNlcm5hbWUiOiJsb29uZyJ9 signature:s2rvfcW5wSvEtCDP0189Sxh7LItbWZKMG2xZ4-Rb220 headerString:{"typ":"JWT","alg":"HS256"} payloadString:{"exp":1643949430,"iat":1643949370,"userid":23,"username":"loong"} nameid:23 username:loong 过期时间为: Fri Feb 04 12:37:10 CST 2022
 
  | 
 
封装工具类
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
   | package com.tothefor.utils;
  import com.auth0.jwt.JWT; import com.auth0.jwt.JWTCreator; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.DecodedJWT;
  import java.util.Calendar; import java.util.Map;
  public class JWTUtils {          private static final String SIG = "123432@#@$#^$^%#^%#89";
      
 
 
 
 
      public static String getToken(Map<String,String> map){         Algorithm alg = Algorithm.HMAC256(SIG);          Calendar ins = Calendar.getInstance();         ins.add(Calendar.DATE,7);                   JWTCreator.Builder builder = JWT.create();                  map.forEach((k,v)->{             builder.withClaim(k,v);         });                  String token = builder.withExpiresAt(ins.getTime()).sign(alg);
          return token;     }
      
 
 
 
      public static DecodedJWT getTokenInfo(String token){         DecodedJWT verify = JWT.require(Algorithm.HMAC256(SIG)).build().verify(token);         return verify;     } }
 
 
  |