JWT(JSON Web Token)源码分析

06-01 1589阅读

Java - JWT的简单介绍和使用

Java JWT:原理、机制及案例示范

什么是JWT?

1.1 JWT的基本概念

JWT(JSON Web Token)是一种用于在各方之间传递JSON格式信息的紧凑、URL安全的令牌(Token)。JWT的主要作用是验证用户身份或权限。它由三部分组成:

  1. Header(头部):标识令牌的类型和加密算法。
  2. Payload(载荷):包含了实际的身份信息及其他数据。
  3. Signature(签名):使用头部和载荷生成的签名,用于验证数据完整性和来源的可靠性。

1.2 JWT的结构

JWT(JSON Web Token)源码分析

JWT的结构由三部分组成,它们通过点号(.)进行分隔,格式如下:

Header.Payload.Signature

具体每一部分的内容如下:

  • Header(头部): 通常包含两部分信息:令牌的类型(JWT)和签名的算法(如HMAC SHA256或RSA)。
    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
    • Payload(载荷): 载荷是JWT的主体部分,包含了需要传输的数据。通常包含以下几种常见的声明(Claims)
      iss:签发者
      exp:过期时间
      sub:主题
      aud:接收者
      iat:签发时间
      nbf:在此之前不可用
      
      • Signature(签名): 签名部分是用来验证消息的完整性,并确保其未被篡改。签名的生成方式如下:
        HMACSHA256(
          base64UrlEncode(header) + "." + base64UrlEncode(payload),
          secret)
        

        代码示例

            org.springframework.boot
            spring-boot-starter
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
            com.auth0
            java-jwt
            3.19.1
        
        
        package tool;
        import com.auth0.jwt.JWT;
        import com.auth0.jwt.JWTVerifier;
        import com.auth0.jwt.algorithms.Algorithm;
        import com.auth0.jwt.interfaces.DecodedJWT;
        import org.junit.Test;
        import java.util.Calendar;
        import java.util.HashMap;
        import java.util.List;
        public class JwtToolTest {
            // 秘钥,你可以随便取,可以取的难一点
            public static final String SECRET = "ASD!@#F^%A";
        	//加密
            private static String tokenCreate() {
                HashMap headers = new HashMap();
                // 过期时间,60s
                Calendar expires = Calendar.getInstance();
                expires.add(Calendar.SECOND, 600);
                return JWT.create()
                        // 第一部分Header
                        .withHeader(headers)
                        // 第二部分Payload
                        .withClaim("userId", 20)
                        .withClaim("userName", "LJJ")
                        //相同的key, 会覆盖前面的数据
                        .withClaim("userName", List.of("aaa", "bb"))
                        .withSubject("hahahha")
                        .withExpiresAt(expires.getTime())
                        // 第三部分Signature
                        .sign(Algorithm.HMAC256(SECRET));
            }
            @Test
            public void testTokenCreate() {
                System.out.println(tokenCreate());
            }
        	//解密
            @Test
            public void testReadJWT() {
                // 创建一个验证的对象
                JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET)).build();
                DecodedJWT verify = jwtVerifier.verify(tokenCreate());
                System.out.println(verify.getClaim("userId").asInt());
                System.out.println(verify.getClaim("userName"));
                System.out.println(verify.getSubject());
                System.out.println("过期时间:" + verify.getExpiresAt());
            }
        }
        

        JWTCreator.java

        JWT.create() 会创建 JWTCreator

        public static JWTCreator.Builder create() {
            return JWTCreator.init();
        }
        static JWTCreator.Builder init() {
            return new Builder();
        }
        Builder() {
           this.payloadClaims = new HashMap();
            this.headerClaims = new HashMap();
        }
        

        初始化两个map ,用来存储header 和 payload数据

        提供的with方法最终都是往 payloadClaims 、 headerClaims 中添加key:value数据

        JWT(JSON Web Token)源码分析

        特殊的key数据

        public interface PublicClaims {
            //Header
            String ALGORITHM = "alg";
            String CONTENT_TYPE = "cty";
            String TYPE = "typ";
            String KEY_ID = "kid";
            //Payload
            String ISSUER = "iss";
            String SUBJECT = "sub";
            String EXPIRES_AT = "exp";
            String NOT_BEFORE = "nbf";
            String ISSUED_AT = "iat";
            String JWT_ID = "jti";
            String AUDIENCE = "aud";
        }
        

        加密

        private String sign() throws SignatureGenerationException {
            String header = Base64.getUrlEncoder().withoutPadding().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8));
            String payload = Base64.getUrlEncoder().withoutPadding().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8));
            byte[] signatureBytes = algorithm.sign(header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8));
            String signature = Base64.getUrlEncoder().withoutPadding().encodeToString((signatureBytes));
            return String.format("%s.%s.%s", header, payload, signature);
        }
        

        verify(解密校验)

        // JWTVerifier.java
        @Override
        public DecodedJWT verify(String token) throws JWTVerificationException {
            DecodedJWT jwt = new JWTDecoder(parser, token);
            return verify(jwt);
        }
        @Override
        public DecodedJWT verify(DecodedJWT jwt) throws JWTVerificationException {
            verifyAlgorithm(jwt, algorithm);
            algorithm.verify(jwt);
            verifyClaims(jwt, claims);
            return jwt;
        }
        private void verifyClaims(DecodedJWT jwt, Map claims) throws TokenExpiredException, InvalidClaimException {
            for (Map.Entry entry : claims.entrySet()) {
                if (entry.getValue() instanceof NonEmptyClaim) {
                    assertClaimPresent(jwt.getClaim(entry.getKey()), entry.getKey());
                } else {
                    verifyClaimValues(jwt, entry);
                }
            }
        }
        

        最终根据特殊的key来校验token

        private void verifyClaimValues(DecodedJWT jwt, Map.Entry expectedClaim) {
            switch (expectedClaim.getKey()) {
                // We use custom keys for audience in the expected claims to differentiate between validating that the audience
                // contains all expected values, or validating that the audience contains at least one of the expected values.
                case AUDIENCE_EXACT:
                    assertValidAudienceClaim(jwt.getAudience(), (List) expectedClaim.getValue(), true);
                    break;
                case AUDIENCE_CONTAINS:
                    assertValidAudienceClaim(jwt.getAudience(), (List) expectedClaim.getValue(), false);
                    break;
                case PublicClaims.EXPIRES_AT:
                    assertValidDateClaim(jwt.getExpiresAt(), (Long) expectedClaim.getValue(), true);
                    break;
                case PublicClaims.ISSUED_AT:
                    assertValidDateClaim(jwt.getIssuedAt(), (Long) expectedClaim.getValue(), false);
                    break;
                case PublicClaims.NOT_BEFORE:
                    assertValidDateClaim(jwt.getNotBefore(), (Long) expectedClaim.getValue(), false);
                    break;
                case PublicClaims.ISSUER:
                    assertValidIssuerClaim(jwt.getIssuer(), (List) expectedClaim.getValue());
                    break;
                case PublicClaims.JWT_ID:
                    assertValidStringClaim(expectedClaim.getKey(), jwt.getId(), (String) expectedClaim.getValue());
                    break;
                case PublicClaims.SUBJECT:
                    assertValidStringClaim(expectedClaim.getKey(), jwt.getSubject(), (String) expectedClaim.getValue());
                    break;
                default:
                    assertValidClaim(jwt.getClaim(expectedClaim.getKey()), expectedClaim.getKey(), expectedClaim.getValue());
                    break;
            }
        }
        
免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码