zoukankan      html  css  js  c++  java
  • JWT

    JWT简介

    什么是JWT

    JSON Web Token(JWT)是一个开放的行业标准(RFC 7519),定义了一种简介的,自包含的协议格式,用于在通信双方传递json对象,传递的信息经过数字签名可以被验证和信任,JWT可以使用HMAC算法
    或使用RSA的公钥/私钥来签名,防止被篡改

    官网: https://jwt.io

    标准: https://tools.ietf.org/html/rfc7519

    JWT令牌的优点:
    1.jwt基于json,非常方便解析
    2.可以在令牌中自定义丰富的内容,易扩展
    3.通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高
    4.资源服务使用JWT可不依赖认证服务即可完成授权
    缺点:
    1.JWT令牌较长,占存储空间比较大

    JW 了组成

    JWT 实际上就是一个字符串 · 它由三部分组成,头部、荷载与签名

    头部(Header )

    头部用于描述关于该 JWT 的最基本的信息,例如其类型(即 JWT )以及签名所用的算法(如 HMAC SHAZS6 或 RSA ) 等.这也可以被表示成一个 JS0N 对象.
    {
    "alg" : "HS256"
    "typ" : " JWT"
    }

    • typ :是类型
    • alg :签名的算法,这里使用的算法是HS5256 算法
      我们对头部Json 字符串进行 BASE64 编码(网上有很多在线编码的网站),编码后的字符串如下:
      eyJhbGci0lJIUzI1NiIsInR5cCI6IkpXVCJ9
      Base64 是一种基于64个可打印字符来表示二进制数据的表示方法。
      由于 2 的 6 次方等于 64 ,所以每 6 个比特为一单元对应某个可打印字符.三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符采
      表示。JDK中提供了非案方便的BASE64Encode「和BASE64Decoder ,用它们可以非常方便的完成基于BASE64
      的编码和解码,

    负载(Payload)

    第二部分是负载,就是存放有效信息的地方.这个名字像是特指飞机上承载的货品这些有效信息包含三个部分:

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

    iss:签发者
    sub: jwt所面向61用户
    aud:接收]的一方
    exp: 的过期时间,这个道明叼间必纪要大于签发叼问
    nbf:定义在什么叼间之前,该jwt都是不可用的.
    iat: jwt的签发时间
    jti: jwt的咆一身份而识,主要用未作为一次性token,从而回应重放攻击

    • 公共的声明
      公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信
      息,因为该部分在客户端可解变.
    • 私有的声明
      私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解空的,意味看该
      部分信息可以归类为明文信息。 J I
      这个指的就是自定义的claim。比如下面那个举例中的name都属于自定的claim.这些claim跟JWT标准规定的
      claim区别在于:JWT规定的claim, JWT的接收方在拿到JWT之后,都知道怎么对这些标准的claim进行验证(还不知
      道是否能够验证);而private claim本会验证,除非明确告诉接收方要对这些claim进行验证以及规则才行。

    {
    Hsub-: 1234567890”,
    "name": "John Doe*,
    Miat": 1516239022
    }

    其中sub是标准的声明,name是自定义的声明(公共的或私有的)
    然后将其进行base64编码,得到JwtM第二部分:

    eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbWVzIiwiYWRtaW4iOnRydWV9

    提示:声明中不要放一些敏感信息。

    签证、签名(signature)

    jwtM第三部分是一个受证信息,这个签证信息由三部分组成:

    1. header (base64后的)
    2. payload (base64后的)
    3. secret (盐,一定要保密)
      这个部分需要base64加空后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明
      的加密方式进行加盐secret组合加空,然后就构成了jwt的第三部分:
      8HI-Lod0ncfVDnbKIPJJqLH998duF9DSDGkx3gRPNVI
      将这三部分用.连接成一个完整的字符串,构成了最终的jwt:
      eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9HiwiaWF0Ij
      oxNTE2MjM5MDIyfQ.8HI-Lod0ncfVDnbKIPJJqLH998duF9DSDGkx3gRPNVI
      注意:secret是保存研员务器端的,的签发生成也是在服务器端的,secret就是用来进行jwt的签发和
      jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流筮出去.一旦客户端得知这个secret,那就
      意味看客户端是可以自我签发jwt 了。

    JJWT简介

    什么是JJWT

    JJWT是i 盘供流到端的JWT创建和验证的Java库,小近免费和开源(Apache license版工2 0), JJW泡容易使用
    和理怅,它被设计成以建筑力中心的流畅界面,隐藏了它的才部分复杂性.
    规范官网 https://jwt.io

    快速入门

    token的创建

    maven依赖

        <parent>
            <artifactId>spring-boot-starter-parent</artifactId>
            <groupId>org.springframework.boot</groupId>
            <version>2.3.12.RELEASE</version>
            <relativePath/>
        </parent>
        <groupId>org.rzk</groupId>
        <artifactId>JWT-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--jwt依赖-->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>0.9.0</version>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
    

    创建token

    由于时间戳不一样 Date ,所生成的token也不一样

        /**
         * 创建token
         */
        @Test
        public void JwtTestBuild(){
            JwtBuilder jwtBuilder = Jwts.builder()
                    //设置Id {"jti":"888"}
                    .setId("888")
                    //签发用户 {"sub":"888"}
                    .setSubject("Rose")
                    //签发时间 {"iat":"888"}
                    .setIssuedAt(new Date())
                    //盐
                    .signWith(SignatureAlgorithm.HS256,"abcd");
            String token = jwtBuilder.compact();
            System.out.println(token);
            String[] split = token.split("\\.");
            //头部
            System.out.println(Base64Codec.BASE64.decodeToString(split[0]));
            //负载
            System.out.println(Base64Codec.BASE64.decodeToString(split[1]));
            //签名,乱码
            System.out.println(Base64Codec.BASE64.decodeToString(split[2]));
        }
    

    eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjQxNDAwMTUyfQ.sT0LtxqdOrV3E_8gZK_iCWZtjof8hFRnP-3R0ACc5P0
    {"alg":"HS256"}
    {"jti":"888","sub":"Rose","iat":1641400152
    �= ��:�w�* �f���EFs�G@s��

    解析token

        @Test
        public void parseToken(){
            String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjQxNDAwMTUyfQ.sT0LtxqdOrV3E_8gZK_iCWZtjof8hFRnP-3R0ACc5P0";
            //获取claims荷载
            Claims body = Jwts.parser()
                    .setSigningKey("abcd")
                    .parseClaimsJws(token).getBody();
            System.out.println("jti:"+body.getId());
            System.out.println("sub:"+body.getSubject());
            System.out.println("iat:"+body.getIssuedAt());
        }
    

    jti:888
    sub:Rose
    iat:Thu Jan 06 00:29:12 CST 2022

    创建token时加过期时间

     /**
         * 创建token  过期时间
         */
        @Test
        public void JwtTestBuildExp(){
            long timeMillis = System.currentTimeMillis();
            //过期时间  一分钟
            long expTime = timeMillis + 60 * 1000;
            JwtBuilder jwtBuilder = Jwts.builder()
                    //设置Id {"jti":"888"}
                    .setId("888")
                    //签发用户 {"sub":"888"}
                    .setSubject("Rose")
                    //签发时间 {"iat":"888"}
                    .setIssuedAt(new Date())
                    //盐
                    .signWith(SignatureAlgorithm.HS256, "abcd")
                    //过期时间
                    .setExpiration(new Date(expTime));
            String token = jwtBuilder.compact();
            System.out.println(token);
            String[] split = token.split("\\.");
            //头部
            System.out.println(Base64Codec.BASE64.decodeToString(split[0]));
            //负载
            System.out.println(Base64Codec.BASE64.decodeToString(split[1]));
            //签名,乱码
            System.out.println(Base64Codec.BASE64.decodeToString(split[2]));
        }
    

    eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjQxNDAwNTU3LCJleHAiOjE2NDE0MDA2MTd9.KpbHFkAb6Ov3QWyPM1IIODWWI4L7WzOakqSmYRYtKRs
    {"alg":"HS256"}
    {"jti":"888","sub":"Rose","iat":1641400557,"exp":1641400617}
    *��@���Al�385�#��[3����a-

    解析带过期时间的token

        //解析token 过期时间
        @Test
        public void parseTokenExp(){
            String token = "eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiJSb3NlIiwiaWF0IjoxNjQxNDAwNTU3LCJleHAiOjE2NDE0MDA2MTd9.KpbHFkAb6Ov3QWyPM1IIODWWI4L7WzOakqSmYRYtKRs";
            //获取claims荷载
            Claims body = Jwts.parser()
                    .setSigningKey("abcd")
                    .parseClaimsJws(token).getBody();
            System.out.println("jti:"+body.getId());
            System.out.println("sub:"+body.getSubject());
            System.out.println("iat:"+body.getIssuedAt());
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
            System.out.println("当前时间:"+format.format(new Date()));
            System.out.println("过期时间:"+format.format(body.getExpiration()));
    
        }
    

    jti:888
    sub:Rose
    iat:Thu Jan 06 00:35:57 CST 2022
    当前时间:2022-01-06 00:36:45
    过期时间:2022-01-06 00:36:57

    如果在过期之后解析token的话

    会报失效JWT异常
    JWT失效时间在2022-01-06T00:36:57Z 当前时间 2022-01-06T00:37:47Z 超过50003 milliseconds
    JWT expired at 2022-01-06T00:36:57Z. Current time: 2022-01-06T00:37:47Z, a difference of 50003 milliseconds. Allowed clock skew: 0 milliseconds.

  • 相关阅读:
    Django之templates模板
    Django视图函数之request请求与response响应对象
    Django视图函数之三种响应模式
    Django视图函数函数之视图装饰器
    django 获取request请求对象及response响应对象中的各种属性值
    Django 项目中设置缓存
    python 中 使用sys模块 获取运行脚本时在命令行输入的参数
    Mac 设置终端中使用 sublime 打开文件
    iterm2 恢复默认设置
    Python replace方法的使用
  • 原文地址:https://www.cnblogs.com/rzkwz/p/15769470.html
Copyright © 2011-2022 走看看