12【hutool】hutool-jwt

2,651 阅读2分钟

该系列文章主要是对 hutool 工具类的介绍,详情可以参考

hutool.cn/docs

hutool 提供了零依赖的JWT(JSON Web Token)实现。

  • jwt 结构
  • Header 头部信息,主要声明了JWT的签名算法等信息
  • Payload 载荷信息,主要承载了各种声明并传递明文数据
  • Signature 签名,拥有该部分的JWT被称为JWS,也就是签了名的JWS,用于校验数据

JWT 头

JWT 头部分是一个描述 JWT 元数据的 JSON 对象,通常如下所示。

{ "alg": "HS256", "typ": "JWT" }

alg 属性表示签名使用的算法,默认为 HMAC SHA256(写为 HS256)

typ 属性表示令牌的类型,JWT 令牌统一写为 JWT。

最后,使用 Base64 URL 算法将上述 JSON 对象转换为字符串保存。

有效载荷

有效载荷部分,是JWT的主体内容部分,也是一个JSON对象,包含需要传递的数据。 JWT指定七个默认字段供选择。

  • iss:发行人
  • exp:到期时间
  • sub:主题
  • aud:用户
  • nbf:在此之前不可用
  • iat:发布时间
  • jti:JWT ID用于标识该JWT

请注意,默认情况下JWT是未加密的,任何人都可以解读其内容,因此不要构建隐私信息字段,存放保密信息,以防止信息泄露。

JSON对象也使用Base64 URL算法转换为字符串保存。

签名哈希

签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。

首先,需要指定一个密码(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用标头中指定的签名算法(默认情况下为HMAC SHA256)根据以下公式生成签名。

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象。

主要提供的功能:

  • JWT创建
  • JWT解析
  • JWT验证
    @Test
    public void createTest() {
        byte[] key = "helloworld".getBytes();
        Map<String, Object> map = new HashMap<String, Object>() {
            private static final long serialVersionUID = 1L;

            {
                put("uid", Integer.parseInt("123"));
                // 10 秒后失效
                put(JWTPayload.EXPIRES_AT, System.currentTimeMillis() + 1000 * 10);

            }
        };
        String token = JWTUtil.createToken(map, key);
        Console.log(token);
    }

    @Test
    public void parseTest() {
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEyMywiZXhwIjoxNjYzNzI2Mzg2NTQ0fQ.yZtjlrV5hN8hWdFOZLJNqoaNaand-1XW0Pi1YIwmCrk";
        final JWT jwt = JWTUtil.parseToken(token);
        //header
        JSONObject headers = jwt.getHeaders();
        Console.log(headers);
        //payload
        JSONObject payloads = jwt.getPayloads();
        Console.log(payloads);
    }

    @Test
    public void verifyTest() {
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEyMywiZXhwIjoxNjYzNzI2Mzg2NTQ0fQ.yZtjlrV5hN8hWdFOZLJNqoaNaand-1XW0Pi1YIwmCrk";
        final boolean verify = JWTUtil.verify(token, "helloworld".getBytes());
        Assert.assertTrue(verify);
    }

    @Test
    public void validateTest() {
        JWT jwt = JWT.create()
                .setPayload("test", "test")
                .setKey("helloworld".getBytes(StandardCharsets.UTF_8))
                .setIssuedAt(DateUtil.date())
                .setExpiresAt(DateUtil.parse("2022-09-21 10:37:00"));
        String token = jwt.sign();
        ThreadUtil.safeSleep(1000 * 60);
        JWTValidator.of(token).validateDate();
    }