JWT的学习和JJWT的使用

1.什么是JWT

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

官网: https://jwt.io/

JWT令牌的优点:

  • jwt基于json,非常方便进行解析
  • 可以在令牌中自定义丰富的内容,更容易进行扩展
  • 通过非对称加密算法和数字签名技术,JWT防止篡改,安全性高

JWT令牌的缺点:

  • JWT令牌较长,所占的存储空间比较大。

2.JWT的组成

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

2.1JWT的头部(Header)

头部用于描述关于该JWT的最基本信息,例如其类型(即JWT)以及签名所用的算法(HMAC,SHA256,RSA)等等

{
    "alg":"HS256""typ":"JWT"
}
  • alg:表示签名使用的算法
  • typ:类型

我们对头部的json字符串进行BASE64编码后就能得到一个字符串,JDK中提供了非常方便的BASE64EncoderBASE64Decoder,用它们可以非常方便的完成基于BASE64的编码和解码。

2.2载荷(Payload)

第二部分的内容是载荷,就是存放有效信息的地方,这些有效信息包含三个部分

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

    iss: jwt的签发者
    sub: jwt所面向的用户
    aud: 接收jwt的一方
    exp: jwt的过期时间,这个过期时间必须大于签发时间
    iat: jwt的签发时间
    nbf: 定义在什么时间之前,这个jwt都是不可用的
    jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
    
  2. 公共的声明

    ​ 公共的声明可以添加任何的信息,一般添加用户的相关信息或者其他业务需要的必要信息, 但不建议添加敏感的信息,因为载荷可以解密。

  3. 私有的声明

    ​ 私有声明是提供者和消费者所共同定义的声明,一般还是不建议存放敏感的信息,因为base64是对称解密的,意味着这一部分的信息可以归类为明文信息。

自定义claim,比如下面例子中的name就属于自定义的claim。这些claim跟JWT标准规定的claim区别在于:JWT规定的claim在接收方拿到JWT后,都知道怎么对标准的claim进行验证,而私有的claim不会验证,除非明确告诉接收方要对这些claim进行验证以及验证的规则才行。

{
    "sub":"2390866852",
    "name":"Test",
    "iat":"12312323"
}

上面的name是自定义的声明(公共的或者私有的),而另外两部分是标准的声明

2.3签证,签名(signature)

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

  1. header(base64编码后的)
  2. payload(base64编码后的)
  3. secret(盐,一定要保密)

​ 这个部分需要base64加密后的header和payload使用**.**连接组成的字符串,然后通过header中声明的加密模式进行加盐secret组合加密,形成一个完整的签证

将这三个部分用 . 连接拼成一个完整的字符串,也就是最终的jwt

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

3.JJWT快速使用

jjwt是jwt在java中的主流应用,下面将实现一个demo进行学习

新建第一个springboot的项目进行测试

pom.xml

        <!-- https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

3.1创建token

    /**
     * 创建token
     */
    @Test
    public void testCreateToken() {
        //创建JwtBuilder对象
        JwtBuilder jwtBuilder = Jwts.builder()
                //声明的唯一标识{"jti":"6666"}
                .setId("6666")
                //主体,面向的用户{"sub":"Test"}
                .setSubject("Test")
                //签发时间{"iat":"xxxxx"}
                .setIssuedAt(new Date())
                //签证
                .signWith(SignatureAlgorithm.HS256, "scret");
        //获取jwt的token
        String token = jwtBuilder.compact();
        System.out.println(token);

        System.out.println("======================");
        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]));
    }

3.2解析token

    /**
     * 解析token
     */
    @Test
    public void testParesToken() {
        String token = "eyJhbGciOiJIUzI1NiJ9." +
                "eyJqdGkiOiI2NjY2Iiwic3ViIjoiVGVzdCIsImlhdCI6MTY2MzIxMTA3Mn0." +
                "BcbZ2T_kmFg94-L3z1TXCCEDln1qwX-F9cPs9WiK8Fc";
        //解析token获取负载中声明的对象
        Claims claims = Jwts.parser()
                .setSigningKey("scret")
                .parseClaimsJws(token)
                .getBody();
        System.out.println("id:" + claims.getId());
        System.out.println("sub:" + claims.getSubject());
        System.out.println("issuedAt:" + claims.getIssuedAt());
    }

运行解析token得到如下结果:

在这里插入图片描述

3.3创建有失效时间的token

    /**
     * 创建token(失效时间)
     */
    @Test
    public void testCreateTokenHasExp() {
        //当前系统时间
        long now = System.currentTimeMillis();
        //失效时间(当前系统时间+1分钟)
        long exp = now + 60 * 1000;
        //创建JwtBuilder对象
        JwtBuilder jwtBuilder = Jwts.builder()
                //声明的唯一标识{"jti":"6666"}
                .setId("6666")
                //主体,面向的用户{"sub":"Test"}
                .setSubject("Test")
                //签发时间{"iat":"xxxxx"}
                .setIssuedAt(new Date())
                //签证
                .signWith(SignatureAlgorithm.HS256, "scret")
                //失效时间{"exp":"xxxxx"}
                .setExpiration(new Date(exp));
        //获取jwt的token
        String token = jwtBuilder.compact();
        System.out.println(token);

        System.out.println("======================");
        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]));
    }

3.4解析有失效时间的token

    /**
     * 解析token(失效时间)
     */
    @Test
    public void testParesTokenHasExp() {
        String token = "eyJhbGciOiJIUzI1NiJ9." +
                "eyJqdGkiOiI2NjY2Iiwic3ViIjoiVGVzdCIsImlhdCI6MTY2MzIxMjEwMiwiZXhwIjoxNjYzMjEyMTYyfQ." +
                "PKH59MVUuwmkBWTw7cCN3L3eg_atHaCGwuoe5wNQbJs";
        //解析token获取负载中声明的对象
        Claims claims = Jwts.parser()
                .setSigningKey("scret")
                .parseClaimsJws(token)
                .getBody();
        System.out.println("id:" + claims.getId());
        System.out.println("sub:" + claims.getSubject());
        System.out.println("issuedAt:" + claims.getIssuedAt());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("签发时间:" + simpleDateFormat.format(claims.getIssuedAt()));
        System.out.println("过期时间:" + simpleDateFormat.format(claims.getExpiration()));
        System.out.println("当前时间:" + simpleDateFormat.format(new Date()));
    }

当设置的token已经失效后,会出现如下错误:

在这里插入图片描述

3.5创建自定义token

    /**
     * 创建token(自定义)
     */
    @Test
    public void testCreateTokenByClaims() {
        //创建JwtBuilder对象
        JwtBuilder jwtBuilder = Jwts.builder()
                //声明的唯一标识{"jti":"6666"}
                .setId("6666")
                //主体,面向的用户{"sub":"Test"}
                .setSubject("Test")
                //签发时间{"iat":"xxxxx"}
                .setIssuedAt(new Date())
                //签证
                .signWith(SignatureAlgorithm.HS256, "scret")
                //自定义声明
                .claim("role", "admin")
                .claim("info", "top");
        //获取jwt的token
        String token = jwtBuilder.compact();
        System.out.println(token);

        System.out.println("======================");
        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]));
    }

3.6解析自定义token

    /**
     * 解析token(自定义)
     */
    @Test
    public void testParesTokenByClaims() {
        String token = "eyJhbGciOiJIUzI1NiJ9." +
                "eyJqdGkiOiI2NjY2Iiwic3ViIjoiVGVzdCIsImlhdCI6MTY2MzIxMjUxNCwicm9sZSI6ImFkbWluIiwiaW5mbyI6InRvcCJ9." +
                "v69wR_j8HXXto0A5QPl6paQDZaHSrBwZ-QZtTwvi6dw";
        //解析token获取负载中声明的对象
        Claims claims = Jwts.parser()
                .setSigningKey("scret")
                .parseClaimsJws(token)
                .getBody();
        System.out.println("id:" + claims.getId());
        System.out.println("sub:" + claims.getSubject());
        System.out.println("issuedAt:" + claims.getIssuedAt());
        System.out.println("role:" + claims.get("role"));
        System.out.println("info:" + claims.get("info"));
    }

解析自定义token信息出现如下结果:

在这里插入图片描述

以上就是在java中对jwt的简单使用,完整源代码在gitee仓库!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值