目录

Java 中使用 JWT

JWT 简介

JSON Web Token ( JWT ) 是一个开放标准 ( RFC 7519 ),它定义了一种紧凑且自包含的方式,用于在各方之间作为 JSON 对象安全地传输信息。该信息可以被验证和信任,因为它是经过数字签名的。JWT 可以使用秘密(使用 HMAC 算法)或使用 RSAECDSA 的公钥/私钥对进行签名1

使用 JWTS 的应用程序不再需要保存有关其用户的 cookie 或其他 session 数据。此特性便于可伸缩性,同时保证应用程序的安全。在身份验证过程中,当用户使用其凭据成功登录时,将返回 JSON Web token,并且必须在本地保存(通常在本地存储中)。每当用户要访问受保护的路由或资源 (端点)时,用户代理(user agent)必须连同请求一起发送 JWT ,通常在授权标头中使用 Bearer schema ,后端服务器接收到带有 JWT 的请求时,首先要做的是验证token。

JWT 格式

  • JWT 就是一个字符串,经过加密处理与校验处理的字符串,形式为:A.B.C 2

  • A 由 JWT 头部信息 header 经过 base64 加密得到

    • 1
      2
      3
      4
      5
      6
      7
      
      # 默认的头信息
      {
        "alg": "HS256",
        "typ": "JWT"
      }
          
      # base64加密后的字符串为:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
      
  • B 是 payload ,存放有效信息的地方,这些信息包含三个部分:

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

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

      • 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分在客户端可解密。
    • 私有的声明

      • 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为 base64 是对称解密的,意味着该部分信息可以归类为明文信息。
    • 1
      2
      3
      4
      5
      6
      7
      8
      9
      
      #存放的数据:
      {
        "sub": "1234567890",
        "name": "John Doe",
        "iat": 1516239022
      }
          
      #base64后的字符串为:
      eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
      
  • C 由 A 和 B 通过加密算法得到,用作对 token 进行校验,看是否有效

    • 这个部分需要 base64 加密后的 header 和 base64 加密后的 payload 使用.连接组成的字符串,然后通过 header 中声明的加密方式进行加盐secret组合加密,然后就构成了 jwt 的第三部分。

    • 1
      2
      3
      4
      
      #secret为:cHVsbmQuY29t
      #得到的加密字符串为:FugClbNNfDvcax8k5KoipoV54PujhR1lnDnB8dSoOQE
          
      #整体的token为:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtb2JpbGUiOiIxMzMzMzMzMzMzMyIsImlkIjoiOCIsImV4cCI6MTYyNTIzMDg3NX0.FugClbNNfDvcax8k5KoipoV54PujhR1lnDnB8dSoOQE
      

JWT 示例

导入依赖:3

1
2
3
4
5
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.11.1</version>
</dependency>

编写测试用例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.pulnd.jwt.test;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwsHeader;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.junit.Test;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class TestJWT {

    String secret = "cHVsbmQuY29t";

    @Test
    public void testCreateToken(){

        Map<String, Object> header = new HashMap<String, Object>();
        header.put(JwsHeader.TYPE, JwsHeader.JWT_TYPE);
        header.put(JwsHeader.ALGORITHM, "HS256");

        Map<String, Object> claims = new HashMap<String, Object>();
        claims.put("mobile", "1333333333");
        claims.put("id", "8");

        // 生成token
        String jwt = Jwts.builder()
                .setHeader(header)  //header,可省略
                .setClaims(claims) //payload,存放数据的位置,不能放置敏感数据,如:密码等
                .signWith(SignatureAlgorithm.HS256, secret) //设置加密方法和加密盐
                .setExpiration(new Date(System.currentTimeMillis() + 1000*60*30)) //设置过期时间,30分钟后过期
                .compact();

        System.out.println(jwt);

    }

    
    @Test
    public void testDecodeToken(){
        String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJtb2JpbGUiOiIxMzMzMzMzMzMzMyIsImlkIjoiOCIsImV4cCI6MTYyNTIzMDg3NX0.FugClbNNfDvcax8k5KoipoV54PujhR1lnDnB8dSoOQE";
        try {
            // 通过token解析数据
            Map<String, Object> body = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
            System.out.println(body); //{mobile=13333333333, id=8, exp=1625230875}
        } catch (ExpiredJwtException e) {
            System.out.println("token已经过期!");
        } catch (Exception e) {
            System.out.println("token不合法!");
        }
    }

}

参考


  1. JSON 网络令牌简介 ↩︎

  2. JSON Web Tokens - jwt.io ↩︎

  3. Java JWT: JSON Web Token for Java and Android ↩︎