• jwt《token》


     payload与claims只能存在一个
    这部分是jwt源码:
    依赖如下:官方文档的依赖
    <dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
    </dependency>


    <dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.2</version>
    </dependency>

    <dependency>
    <groupId>io.jsonwebtoken </groupId >
    <artifactId>jjwt-jackson </artifactId >
    <version>0.11.2</version>
    </dependency>


    2020-11-1217:17:43
    @Override public String compact() { if (this.serializer == null) { // try to find one based on the services available // TODO: This util class will throw a UnavailableImplementationException here to retain behavior of previous version, remove in v1.0 // use the previous commented out line instead this.serializer = LegacyServices.loadFirst(Serializer.class); } if (payload == null && Collections.isEmpty(claims)) {//判断空 payload = ""; } if (payload != null && !Collections.isEmpty(claims)) {//判断空 throw new IllegalStateException("Both 'payload' and 'claims' cannot both be specified. Choose either one."); } Header header = ensureHeader(); JwsHeader jwsHeader; if (header instanceof JwsHeader) {//判断header类型 jwsHeader = (JwsHeader) header; } else { //noinspection unchecked jwsHeader = new DefaultJwsHeader(header); } if (key != null) { //判断加密方式 jwsHeader.setAlgorithm(algorithm.getValue()); } else { //no signature - plaintext JWT: jwsHeader.setAlgorithm(SignatureAlgorithm.NONE.getValue()); } if (compressionCodec != null) { jwsHeader.setCompressionAlgorithm(compressionCodec.getAlgorithmName()); } //header进行base64加密 String base64UrlEncodedHeader = base64UrlEncode(jwsHeader, "Unable to serialize header to json."); //绿色部分表示payload转化base64加密成字节数组进行一次压缩 byte[] bytes; try { bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims); } catch (SerializationException e) { throw new IllegalArgumentException("Unable to serialize claims object to json: " + e.getMessage(), e); } if (compressionCodec != null) { bytes = compressionCodec.compress(bytes); } //对payload压缩后的租界数组再来一次base64加密 String base64UrlEncodedBody = base64UrlEncoder.encode(bytes); //签名拼接 String jwt = base64UrlEncodedHeader + JwtParser.SEPARATOR_CHAR + base64UrlEncodedBody;


    // 加密的key再次判断为不为空 if (key != null) { //jwt must be signed: //签名与拼接 JwtSigner signer = createSigner(algorithm, key); String base64UrlSignature = signer.sign(jwt); jwt += JwtParser.SEPARATOR_CHAR + base64UrlSignature; } else { // no signature (plaintext), but must terminate w/ a period, see // https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-6.1 jwt += JwtParser.SEPARATOR_CHAR; } return jwt; }

            个人模拟加密流程:

    
    
            //0  原始签名
            String header0 = "{"alg":"HS256"}";
            String claims0 = "{"sub":"wangbiao","aud":"wangbiao"}";
    
            Encoder<byte[], String> base64UrlEncoder = Encoders.BASE64URL;
            String hed =base64UrlEncoder.encode(header0.getBytes("UTF-8"));
    
            Map map= (Map) JSON.parse(claims0);
            Serializer<Map<String,?>> serializer= LegacyServices.loadFirst(Serializer.class);
            byte[] clambyte0= serializer.serialize(map);
    
    
            /**
             * payload为空String方法转化字节数组,不然转化JSON序列化,默认payload为null 即上面的序列化
             * bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims);
             * byte [] claimbyte=claims0.getBytes("UTF-8");
             */
    
    
            /**
             *  默认jwt不需要压缩
             *        DeflateCompressionCodeWb deflateCompressionCodecss=new DeflateCompressionCodeWb();
             *        claims压缩字节
             *        byte[]  clambyte1 =deflateCompressionCodecss.doCompress(clambyte0);
             */
    
    //        KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);
            //签名key
            SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
    
    
            //字节在编码
            String cla= base64UrlEncoder.encode(clambyte0);
            String concatenated= hed+'.'+cla;
    
            //签名方式
            SignatureAlgorithm algorithm=SignatureAlgorithm.HS256;
    
    
            JwtSigner defaultJwtBuilder=new DefaultJwtSigner(algorithm,key,base64UrlEncoder);
    
            String base64UrlSignature = defaultJwtBuilder.sign(concatenated);
            String sss= concatenated+'.'+base64UrlSignature;
    //        System.out.println(sss);
            //验签
            System.out.println(Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(sss));
    
    
    

     利用jwt封装的方法:

            //2设置token方式二 设置头
            Header header = new DefaultHeader();
            header.put("alg", "HS256");
    //       //header设置方式1  设置map
            Map<String, Object> claims = new HashMap<>();
            claims.put("aud", "wangbiao");
            claims.put("sub", "wangbiao");
            String jwss = Jwts.builder()
                    .setHeader((Map<String, Object>) header)
                    .setClaims(claims)
                    .signWith(key)
                    .compact();
    //        System.out.println(jwss);
            //验签
            System.out.println(Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(jwss));
    

     个人jwt生成结果:

    eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ3YW5nYmlhbyIsImF1ZCI6IndhbmdiaWFvIn0.Lxso52KaEnj_a7mYAoH0eoPisIpCo_2sBihmf7sHxGw
    jwt封装生成结果:

    eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJ3YW5nYmlhbyIsInN1YiI6IndhbmdiaWFvIn0.weI8QvS16782iZR6Hb3k3kYExmpSyax0a-KRzfG-vFc
    可以看出最后签名不一致

           个人jwt验签解析:

    header={alg=HS256},body={sub=wangbiao, aud=wangbiao},signature=Lxso52KaEnj_a7mYAoH0eoPisIpCo_2sBihmf7sHxGw

          jwt封装眼前解析:

    header={alg=HS256},body={aud=wangbiao, sub=wangbiao},signature=weI8QvS16782iZR6Hb3k3kYExmpSyax0a-KRzfG-vFc

    思考:通过追踪源码:发现默认情况下payload没有进行压缩

    即没有进行如下操作:

    if (compressionCodec != null) {
    bytes = compressionCodec.compress(bytes);
    }
                   payload为bull进行字符String转化为字节数组,不然转化为转化为tojSON(claims)序列化
    bytes = this.payload != null ? payload.getBytes(Strings.UTF_8) : toJson(claims);

    header正常进行base64加密


    猜想:我此处使用main方法测试,同一个线程下jwt签名具有不可重复,或者jwt默认就是签名不可重复

    header={alg=HS256},body={aud=wangbiao, sub=wangbiao},signature=weI8QvS16782iZR6Hb3k3kYExmpSyax0a-KRzfG-vFc

    官方文档有如下说明:意思就是如果在一个系统中使用不同的key需要自己重写,密匙解析器,好处就是方便不同的业务使用不同的加密方法,利用适配器的思想解决不同类型的key从而进行验签

    :看源码太累,有哪位大神按照如下思路出个方案,共同进步

    签名密钥分解器
    如果您的应用程序期望使用不同的键签名的JWSs,您就不会调用setSigningKey方法。相反,您需要实现SigningKeyResolver接口,并通过setSigningKeyResolver方法在JwtParserBuilder上指定一个实例。
    例如:
    SigningKeyResolver signingKeyResolver = getMySigningKeyResolver();
    
    Jwts.parserBuilder ()
    
       .setSigningKeyResolver (signingKeyResolver) / / <—
    
       .build ()
       .parseClaimsJws (jwsString);
    通过扩展SigningKeyResolverAdapter并实现resolveSigningKey(JwsHeader, Claims)方法,可以简化一些事情。例如:
    public class MySigningKeyResolver extends SigningKeyResolverAdapter {
        
        @Override
        public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) {
            // implement me
        }
    }
    JwtParser将在解析JWS JSON之后,但在验证JWS签名之前调用resolveSigningKey方法。这允许您检查JwsHeader并声明任何可以帮助您查找用于验证特定jws的键的信息。这对于具有更复杂安全模型的应用程序非常强大,这些应用程序可能在不同的时间使用不同的密钥,或者针对不同的用户或客户。
    您可能会检查哪些数据?
    JWT规范支持的方法是在创建JWS时在JWS头部设置一个kid (Key ID)字段,例如:
    
    getSigningKey();
    
    getKeyId(signingKey);//任何将密钥与ID关联的机制都可以
    
    jws .builder()
    
       .setHeaderParam (JwsHeader。KEY_ID, keyId) // 1
    
       .signWith (signingKey) / / 2
    
       .compact ();
    然后在解析期间,SigningKeyResolver可以检查JwsHeader以获取kid,然后使用该值从某个地方(比如数据库)查找键。例如:
    public class MySigningKeyResolver extends SigningKeyResolverAdapter {
        
        @Override
        public Key resolveSigningKey(JwsHeader jwsHeader, Claims claims) {
            
            //inspect the header or claims, lookup and return the signing key
            
            String keyId = jwsHeader.getKeyId(); //或任何其他字段,你需要检查        
            Key key = lookupVerificationKey(keyId); //实现我
            
            return key;
        }
    }
    注意,检查jwsHeader.getKeyId()只是查找键的最常见方法—您可以检查任意数量的头字段或声明,以确定如何查找验证键。这完全取决于JWS是如何创建的。
    最后请记住,对于HMAC算法,返回的验证密钥应该是一个秘钥,而对于非对称算法,返回的密钥应该是一个公钥(而不是一个私钥)。
    
    一点点学习,一丝丝进步。不懈怠,才不会被时代淘汰
  • 相关阅读:
    weka 文本分类(1)
    python 笔记1
    PAT乙级 1028. 人口普查(20)
    PAT乙级 1027. 打印沙漏(20)
    PAT乙级 1026. 程序运行时间(15)
    Eclipse常用快捷键
    MyBatis源码分析(各组件关系+底层原理
    springmvc异常处理
    Elasticsearch学习(一)————简单命令
    mybatis传入参数类型parameterType详解
  • 原文地址:https://www.cnblogs.com/wangbiaohistory/p/13965099.html
Copyright © 2020-2023  润新知