Java使用JWT开源库

一、JWT简介

JWT官方文档:

  • https://jwt.io/
  • https://jwt.io/introduction/

1、什么是JWT

图片来自官方文档,解释的很清楚了。
Java使用JWT开源库_第1张图片

通俗地说,JWT的本质就是一个字符串,它是将用户信息保存到一个 Json字符串中,然后进行编码后得到一个JWT token,并且这个 JWT token带有签名信息,接收后可以校验是否被篡改,所以可以用于在各方之间安全地将信息作为 Json对象传输。

2、JWT组成部分

在其紧凑的形式中,JWT由以点 ( .) 分隔的三部分组成,它们是:

  • 标头(Header)、
  • 有效载荷(Payload)
  • 签名(Signature)。

在输出时,会将 JWT的 各部分进行 Base64编码后用点 ( .) 进行连接形成最终传输的字符串。

JWTString=
Base64(Header).
Base64(Payload).
HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)

官方首页有查看 JWT Token字符串的解析内容。

2.1 Header

JWT标头是一个描述 JWT元数据的 JSON对象。
通常由两部分组成:令牌的类型,即 JWT,以及正在使用的签名算法,例如 HMAC SHA256 或 RSA。

  • alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256);
  • typ属性表示令牌的类型,JWT令牌统一写为JWT。
    最后,使用 Base64 URL算法将上述 JSON对象转换为字符串保存,即形成 JWT 的第一部分。

比如:

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

2.2 Payload

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

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

这些预定义的字段并不要求强制使用。除以上默认字段外,我们还可以自定义私有字段,一般会把包含用户信息的数据放到 payload中。

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

最后,对有效负载进行 Base64Url编码以形成 JSON Web 令牌的第二部分。

请注意:对于已签名的令牌,此信息虽然受到保护以防篡改,但任何人都可以读取。除非已加密,否则请勿将机密信息放入 JWT 的有效负载或标头元素中。

2.3 Signature

签名部分是对上面两个部分数据进行哈希,需要使用 base64编码后的 header和 payload数据,通过指定的算法生成哈希签名,以确保数据不会被篡改。

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

例如,如果您想使用 HMAC SHA256 算法,签名将通过以下方式创建:

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

签名用于验证消息在此过程中没有被篡改,并且在使用私钥签名的令牌的情况下,它还可以验证 JWT 的发送者就是它所说的那个人。

JWT Token就是将 JWT的 3部分分别进行 Base64编码后用点 ( .) 进行连接形成最终传输的 Base64-URL 字符串。可以在 HTML 和 HTTP 环境中轻松传递,同时与基于 XML 的标准(如 SAML)相比更紧凑。

二、Java使用 JWT开源库

官网推荐了 6个 Java使用 JWT的开源库,其中比较推荐使用的是 java-jwt和 jjwt-root。

  • java-jwt
  • jose4j
  • nimbus-jose-jwt
  • jjwt-root
  • fusionauth-jwt
  • vertx-auth-jwt

通常根据使用的签名算法可以分为对称签名和非对称签名来生成 JWT Token,主要区别在于使用的算法。推荐使用非对称加密算法签名。

1、使用java-jwt

首先引入依赖:

      	  
		<dependency>
            <groupId>com.auth0groupId>
            <artifactId>java-jwtartifactId>
            <version>3.18.2version>
        dependency>

1.1 对称签名

这里使用 HMAC256对称算法。

1.1.1 生成JWT Token

public class JavaJwtLearn1 {

    private static final String SECRET_KEY = "secret_salt";

    public static void main(String[] args) {
        // 指定token过期时间为10秒
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 10);
        Date expiresDate = calendar.getTime();

        String jwtToken = genetatetJwtToken(expiresDate);
        System.out.println("生成 jwtToken=" + jwtToken);
    }

    /**
     * 生成token
     * @param expiresDate
     * @return
     */
    private static String genetatetJwtToken(Date expiresDate ) {

        String jwtToken = JWT.create()
                // Header
                .withHeader(new HashMap<>())
                // Payload
                .withClaim("userId", 21)
                .withClaim("userName", "admin")
                // 过期时间
                .withExpiresAt(expiresDate)
                // 签名用的secret
                .sign(Algorithm.HMAC256(SECRET_KEY));

        return jwtToken;
    }
}

Java使用JWT开源库_第2张图片
注意:

  • 每次生成的 JWT Token字符串内容是不一样的,尽管我们的 payload信息没有变动。因为 JWT中携带了超时时间,所以每次生成的 JWT Token就会不一样。
  • Header和 Payload除了有默认值,我们也可以放置自定义的值。

1.1.2 解析JWT Token

public class JavaJwtLearn1 {

    private static final String SECRET_KEY = "secret_salt";

    public static void main(String[] args) {
        // 指定token过期时间为10秒
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 10);
        Date expiresDate = calendar.getTime();

        String jwtToken = genetatetJwtToken(expiresDate);
        System.out.println("生成 jwtToken=" + jwtToken);

        resolveJwtToken(jwtToken);        
    }

    /**
     * 解析token
     * @param jwtToken
     */
    private static void resolveJwtToken(String jwtToken) {
        // 创建解析对象,使用的算法和secret要与创建token时保持一致
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(SECRET_KEY)).build();
        // 解析指定的token
        DecodedJWT decodedJWT = jwtVerifier.verify(jwtToken);
        // 获取解析后的token中的信息
        String header = decodedJWT.getHeader();
        System.out.println("header:" + header);
        Map<String, Claim> payloadMap = decodedJWT.getClaims();
        System.out.println("Payload:" + payloadMap);
        Date expires = decodedJWT.getExpiresAt();
        System.out.println("过期时间:" + expires);
        String signature = decodedJWT.getSignature();
        System.out.println("signature:" + signature);

    }
}

注意:

  • 如果在过期时间之内解析 JWT Token,则解析成功,否则就会报错。
  • 如果不是JWT Token字符串,也会报错。
    Java使用JWT开源库_第3张图片
    所以,我们可以根据报错来校验 JWT Token的合法性。

1.1.3 判断 JWT Token是否存在与有效

    /**
     * 判断token是否存在与有效
     * @param jwtToken token字符串
     * @return 如果token有效返回true,否则返回false
     */
    public static boolean checkToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) {
            return false;
        }
        try {
            JWT.require(Algorithm.HMAC256(SECRET_KEY)).build().verify(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

1.2 非对称签名

这里使用 RSA非对称加密算法。使用同上。

注意:

  • 提前准备好秘钥对(根据需要密钥(盐)生成)。私钥生成 JWT Token,公钥解析 JWT Token
  • Header和 Payload除了有默认值,我们也可以放置自定义的值。
/**
 * 使用 java-jwt开源库 非对称加密算法签名
 *
 */
public class JavaJwtLearn2 {

	private static final String RSA_PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAIR4W9EIR4mNBrXu6cyw7ninv4koTUTHSlB9bAcvUqVcbRfK2ZWyojgEMNjUcTSYXmWS4RwWSDcWr1/ZbaksY8UNcK2cNk81YuL3CHRl4tOoA5YfKBwDn8q6xbX/bjDPK65hr/eGBUCvdW8ZPbKVLJujpoHEeM28yzMiCv0Igik/AgMBAAECgYA6jZjIBIjaW+Ojdz8QowRFgKBA1/ePdyd5/HZLlrdJMFloMtmKObNKX0/YB88iGFdhPlMSPycccoKCM3EtXdmbEPNYPJDcOqOH+NyqdVP7mDw2KJ7ulSMGINuW/4MGqTecUdL01BAX3KlgwuJu6BzRiPMoWY/LEqYoUmHeedxBwQJBAOgKQ5J/A1ZRFHsyFGYwBY8LJcOGb/yEkawEEOn+yRVy16t+o5R3YFdbHwuWlFVFAys9rXxd4dBLQZI+dZQNZysCQQCSJhFh8DOpVzWqPtadFmlQipZZ48hFcsoq8zS3UTukhxaubBcmvzB5dixQFNOj1veCVic9f8SF57P6dsOWJ7w9AkEA0Aq70PIOBOsHKPmarpApu7mr7yVu7IHTtd2jaJjmo1NnKLyPX4K0nz30lMg6UEVi9PcEv7fQyZdfwAY+FzL5JwJADHj1OM+ACS6pJMtSE3vrJvV82VUILW0bdcjlsdNb7LGerOoKm8LrRyJfq8HrQetBmjzyAlyaD/dzM6fZD0J63QJBALR93M3+EItlV6QxeVGHi7sVyxHYlDlwsIIQPFZB12292blXzygWPCAC1b1BF4KbENN8yPmTL+0ixkRoxRojD8Q=";

	private static final String RSA_PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCEeFvRCEeJjQa17unMsO54p7+JKE1Ex0pQfWwHL1KlXG0XytmVsqI4BDDY1HE0mF5lkuEcFkg3Fq9f2W2pLGPFDXCtnDZPNWLi9wh0ZeLTqAOWHygcA5/KusW1/24wzyuuYa/3hgVAr3VvGT2ylSybo6aBxHjNvMszIgr9CIIpPwIDAQAB";

	public static void main(String[] args) throws Exception {
		// 指定token过期时间为10秒
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.SECOND, 10);
		Date expiresDate = calendar.getTime();


		Map<String,String> payload = new HashMap<>();
		payload.put("userId", "21");
		payload.put("userName", "admin");
		payload.put("userName2", "admin2");
		payload.put("userName3", "admin3");
		String jwtToken = genetatetJwtToken(expiresDate, payload);
		System.out.println("生成 jwtToken=" + jwtToken);

		// jwtToken =
		// "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwiZXhwIjoxNjQ0NDc0MzY5LCJ1c2VySWQiOjIxfQ.2Tgvta3obNfyqUSlFuZPNuGGBs-stB7NeD-GU2R6Sn8";
		resolveJwtToken(jwtToken);
	}


	/**
	 * 生成token
	 * 
	 * @param expiresDate
	 * @return
	 */
	private static String genetatetJwtToken(Date expiresDate, Map<String,String> payload) throws Exception {

		JWTCreator.Builder builder = JWT.create();
		// Header
		Map<String,Object> a =  new HashMap<>(payload);
		builder.withHeader(a);
		// 构建payload
		payload.forEach((k,v) -> builder.withClaim(k,v));
		// 过期时间
		builder.withExpiresAt(expiresDate);


		// 获取RSA私钥
		RSAPrivateKey privateKey = (RSAPrivateKey) RsaUtils.getPrivateKey(RSA_PRIVATE_KEY);
		// 签名
		String jwtToken = builder.sign(Algorithm.RSA256(null, privateKey));

		return jwtToken;
	}

	/**
	 * 解析token
	 * 
	 * @param jwtToken
	 */
	private static void resolveJwtToken(String jwtToken) throws Exception {
		// 获取RSA公钥
		RSAPublicKey publicKey = (RSAPublicKey) RsaUtils.getPublicKey(RSA_PUBLIC_KEY);
		// 创建解析对象,使用的算法和secret要与创建token时保持一致
		JWTVerifier jwtVerifier = JWT.require(Algorithm.RSA256(publicKey, null)).build();
		// 解析指定的token
		DecodedJWT decodedJWT = jwtVerifier.verify(jwtToken);
		// 获取解析后的token中的信息
		String header = decodedJWT.getHeader();
		System.out.println("header:" + header);
		Map<String, Claim> payloadMap = decodedJWT.getClaims();
		System.out.println("Payload:" + payloadMap);
		Date expires = decodedJWT.getExpiresAt();
		System.out.println("过期时间:" + expires);
		String signature = decodedJWT.getSignature();
		System.out.println("signature:" + signature);

	}

}

2、使用jjwt-root

这里使用 0.11.1版本,引入依赖如下:

       
        <dependency>
            <groupId>io.jsonwebtokengroupId>
            <artifactId>jjwt-apiartifactId>
            <version>0.11.2version>
        dependency>
        <dependency>
            <groupId>io.jsonwebtokengroupId>
            <artifactId>jjwt-implartifactId>
            <version>0.11.2version>
            <scope>runtimescope>
        dependency>
        <dependency>
            <groupId>io.jsonwebtokengroupId>
            <artifactId>jjwt-jacksonartifactId>
            <version>0.11.2version>
            <scope>runtimescope>
        dependency>

注意:
jjwt-root在 0.10版本以后发生了较大变化,pom依赖和部分使用方法都有所变化,并且,0.10版本后强制要求 secretKey满足规范中的长度要求,否则生成 jws时会抛出异常。异常如下:
在这里插入图片描述

标准规范中对各种加密算法的 secretKey的长度有如下要求:
HS256:要求至少 256 bits (32 bytes)
HS384:要求至少384 bits (48 bytes)
HS512:要求至少512 bits (64 bytes)
RS256 and PS256:至少2048 bits
RS384 and PS384:至少3072 bits
RS512 and PS512:至少4096 bits
ES256:至少256 bits (32 bytes)
ES384:至少384 bits (48 bytes)
ES512:至少512 bits (64 bytes)

1.1 对称签名

这里使用 HS256对称算法。

public class JjwtRootLearn1 {

    private static final String SECRET_KEY = "secret_salt_aaaaaaaaaaaaaaa";
    //private static final String SECRET_KEY = "secret_salt_MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCEeFvRCEeJjQa17unMsO54p7+JKE1Ex0pQfWwHL1KlXG0XytmVsqI4BDDY1HE0mF5lkuEcFkg3Fq9f2W2pLGPFDXCtnDZPNWLi9wh0ZeLTqAOWHygcA5/KusW1/24wzyuuYa/3hgVAr3VvGT2ylSybo6aBxHjNvMszIgr9CIIpPwIDAQAB";

    public static void main(String[] args) {
        // 指定token过期时间为10秒
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 30);
        Date expiresDate = calendar.getTime();

        String jwtToken = genetatetJwtToken(expiresDate);
        System.out.println("生成 jwtToken=" + jwtToken);

        resolveJwtToken(jwtToken);
        System.out.println(checkToken(jwtToken));
        jwtToken = "eyJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiIyMSIsInVzZXJOYW1lIjoiYWRtaW4iLCJqdGkiOiJZbVk1TkdOa1pUUXRZVGt4TnkwMFlXTmlMVGsyWTJVdE1EVXdPRFUzTlRVMFlqRTQiLCJleHAiOjE2NDQ0Nzk5ODZ9.5lcaBjsDUxmeNCZOt-LnjCPhAajQPK3b2HF_bAzo2Hk";
        System.out.println(checkToken(jwtToken));
    }

    /**
     * 生成token
     * @param expiresDate
     * @return
     */
    private static String genetatetJwtToken(Date expiresDate ) {

        String jwtToken = Jwts.builder()
                // Header
                .setHeader(new HashMap<>())
                // Payload
                .claim("userId", "21")
                .claim("userName", "admin")
                //.setId(new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes())))
                .setId("id----")
                // 过期时间
                .setExpiration(expiresDate)
                // 签名指定key
                .signWith(Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8)), SignatureAlgorithm.HS256)
                .compact();

        return jwtToken;
    }

    /**
     * 解析token
     * @param jwtToken
     */
    private static void resolveJwtToken(String jwtToken) {

        // 创建解析对象,使用的算法和secret要与创建token时保持一致
        JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8))).build();
        // 解析指定的token
        Jws<Claims> claimsJws = jwtParser.parseClaimsJws(jwtToken);
        // 获取解析后的token中的信息
        JwsHeader header = claimsJws.getHeader();
        System.out.println("header:" + header);
        Claims jwsBody = claimsJws.getBody();
        System.out.println("Payload:" + jwsBody);
        System.out.println("过期时间:" + jwsBody.getExpiration());
        String signature = claimsJws.getSignature();
        System.out.println("signature:" + signature);

    }

    /**
     * 判断token是否存在与有效
     * @param jwtToken token字符串
     * @return 如果token有效返回true,否则返回false
     */
    public static boolean checkToken(String jwtToken) {
        if(StringUtils.isEmpty(jwtToken)) {
            return false;
        }
        try {
            Jwts.parserBuilder().setSigningKey(Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8))).build().parseClaimsJws(jwtToken);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

1.2 非对称签名

这里使用 RSA非对称加密算法。使用同上。

public class JjwtRootLearn2 {

    private static final String RSA_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCZZGWcPP8zrMNA6oNhFTGCO2bEeI7t9syazhbIu7ndOM068iI7D+a9KqdPZBVfLQadF/wGV424YDZSO3jh+6SIQrTFhyOaeDWTfMoEqaahqiX4SbcU/9bfkCHX4NaiW4E/8egngnVq+x/Qg6SraC5AOBWLx6kAsUhgKhSJpqNigVh/n4EPcq6IRa2yZWc+FUahmxB4jTJo3s7exRGAyseXmBi8zP4nT+48eL2jSdMoTm0IbCeymCU5u6EHCuOWlnTSv7akXszwIPtpg+IuYIgxpT9Q0CJZrEFWPdjct50/yqVyZ1FHR+rR3I5WskfdJVVNSI7m139BKrrD9GtrazDjAgMBAAECggEAScuEGtM5j3m5Ab0Q8Z7Jj7bWLQU29gK60mr9iRrPQz91dLtSfoma3zzq+wXSRlSaDu+f/skWVDJtT8hu0oFG2YsF/tWR6lmUpNzvL6kSkkoSNE36d27RyAJGVd5ERB2zo7jUkFVx+cLQvnbmvNPFFH4m13V5t+ySPjlgYgy6I8QHa9embSuTlYeFCZe69CP6dla04kpwJzelfs5nziQ7Biy3B1O6V2Y0VeanTdVPHEXZbCVEOvUeJWVXoMAkkXbpiRglt3ugzK/nct4hkViTxu5RDHF/q29q0AvgmXGXontKVW0ee42JphsTsNSGpOxxuXHErE5i/JrbCIgi8ce3KQKBgQDoCkOSfwNWURR7MhRmMAWPCyXDhm/8hJGsBBDp/skVcterfqOUd2BXWx8LlpRVRQMrPa18XeHQS0GSPnWUDWVrP7JWi2sO+++8zKA7KwEpyuhWDfvjKdQcq9lZ7j7T9KQlCJ8e+lIapy8XWjTM3juqkSoah1KrjWF2FncS7S0h7QKBgQCpOyhrZzIocIXvnJ93dGRh6ozzbZ4KBl9VlNHmNNBs45QXsgE5VaR8byZKCvuOMfr/hUTIxTrEqwYo4P4KqUrM9EDjF67DtUKtEo+Dtrs3NE6RNPkG+/OqlcNul6w28mmzPl8XFjGm/MnR3E+Pjw7EkFvixgLMe+7yG3V5WGiEDwKBgQCf30KDUuOXuzFjWDPZ3EhYMBQKzTunPien3v1QW21sS73wuMY36rAEQBH5x/vXbD8sscgwIfcNrmw1OLeGFFzGMhLLsi9HGaop6MqVOaIJi3XcpLHh59XvEzAj2BSNsMbPhUss6sda+clmS46JgKyXboEV2hrJfBWkaQINlkA8WQKBgH3JrBSRIxYt9VASQfHfgNHLLrOuEd9vtyL8uDv9m8KkMiqetAwy3U1krLgyi6K5AdE19NeqyjDu0mhGPG4eQawwDZ7+tndf3syYVDZZ97Rj29ZQ4p1PX2G3agllEavR6cFCphmZ9JQjp7umnzic5CQ1DSd1eRUXNZed02a70Qv/AoGBAMX6hTPKhIY7FUCsvVOI0+CTgOsWJj+0G8r91Mwg/DPrSsPuQy0x9CLh6XvMzAw3J/d39YUVk47x/i48KVudITcNsn+JAckumlyk3cT01JvMJ0WH/p7lJiLGey54dG4nT/+dvkcpCLQMd0R5IC+/iPo03sNKMqhVUE8xL+ChATJf";

    private static final String RSA_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmWRlnDz/M6zDQOqDYRUxgjtmxHiO7fbMms4WyLu53TjNOvIiOw/mvSqnT2QVXy0GnRf8BleNuGA2Ujt44fukiEK0xYcjmng1k3zKBKmmoaol+Em3FP/W35Ah1+DWoluBP/HoJ4J1avsf0IOkq2guQDgVi8epALFIYCoUiaajYoFYf5+BD3KuiEWtsmVnPhVGoZsQeI0yaN7O3sURgMrHl5gYvMz+J0/uPHi9o0nTKE5tCGwnspglObuhBwrjlpZ00r+2pF7M8CD7aYPiLmCIMaU/UNAiWaxBVj3Y3LedP8qlcmdRR0fq0dyOVrJH3SVVTUiO5td/QSq6w/Rra2sw4wIDAQAB";

    public static void main(String[] args) throws Exception {
        // 指定token过期时间为10秒
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.SECOND, 10);
        Date expiresDate = calendar.getTime();

        String jwtToken = genetatetJwtToken(expiresDate);
        System.out.println("生成 jwtToken=" + jwtToken);

        //jwtToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwiZXhwIjoxNjQ0NDc0MzY5LCJ1c2VySWQiOjIxfQ.2Tgvta3obNfyqUSlFuZPNuGGBs-stB7NeD-GU2R6Sn8";
        resolveJwtToken(jwtToken);
    }

    /**
     * 生成token
     * @param expiresDate
     * @return
     */
    private static String genetatetJwtToken(Date expiresDate ) throws Exception {

        // 获取RSA私钥
        RSAPrivateKey privateKey = (RSAPrivateKey) RsaUtils.getPrivateKey(RSA_PRIVATE_KEY);

		// Header中自定义放点值
        Map<String,Object> payload = new HashMap<>();
        payload.put("userId", "21");
        payload.put("userName", "admin");

        String jwtToken = Jwts.builder()
                // Header
                .setHeader(payload)
                // Payload
                .claim("userId", "21")
                .claim("userName", "admin")
                .setId(new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes())))
                // 过期时间
                .setExpiration(expiresDate)
                // 签名指定私钥
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .compact();

        return jwtToken;
    }

    /**
     * 解析token
     * @param jwtToken
     */
    private static void resolveJwtToken(String jwtToken) throws Exception {
        // 获取RSA公钥
        RSAPublicKey publicKey = (RSAPublicKey) RsaUtils.getPublicKey(RSA_PUBLIC_KEY);

        // 创建解析对象,使用的算法和secret要与创建token时保持一致
        JwtParser jwtParser = Jwts.parserBuilder().setSigningKey(publicKey).build();
        // 解析指定的token
        Jws<Claims> claimsJws = jwtParser.parseClaimsJws(jwtToken);
        // 获取解析后的token中的信息
        JwsHeader header = claimsJws.getHeader();
        System.out.println("header:" + header);
        Claims jwsBody = claimsJws.getBody();
        System.out.println("Payload:" + jwsBody);
        System.out.println("过期时间:" + jwsBody.getExpiration());
        String signature = claimsJws.getSignature();
        System.out.println("signature:" + signature);

    }
}

总结:

  • jjwt-root与 java-jwt对 JWT Token的生成和解析过程中的注意点都挺类似。
  • 请勿将机密信息放入 JWT 的有效负载或标头元素中。
  • 在实际开发中,对于 JWT Token中的 Payload信息,可以封装成对象来方便处理。也可以放入 key,把用户信息作为 value存入 Redis等等。

– 求知若饥,虚心若愚。

你可能感兴趣的:(签名&加解密,#,Spring,Security,JWT,Token)