关键词

Java jwt使用公钥字符串验证解析token锁方法详解

下面是详细讲解“Java jwt使用公钥字符串验证解析token锁方法详解”的完整攻略。

一、什么是JWT

JWT是一种开放的标准(RFC 7519),定义了一种简洁的、自包含的方式用于在各方之间传递信息。该信息可以被验证和信任,因为它是经过数字签名的。JWT可以使用对称加密和非对称加密两种方式进行签名,其中非对称加密使用公钥和私钥进行加密和解密。

JWT包含三个部分:头部、载荷和签名,如下所示:

// 头部
{
  "alg": "HS256",
  "typ": "JWT"
}

// 载荷
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022
}

// 签名
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

其中,头部用于描述JWT的元数据信息,如签名算法(alg)和令牌类型(typ)等。载荷包含实际的用户数据,如用户ID、用户名、过期时间等。签名则用于保证JWT的完整性和真实性,通过对头部、载荷和密钥进行签名,得到签名数据,可以用于校验JWT是否被篡改。

二、使用公钥字符串验证解析JWT

对于使用公钥字符串验证解析JWT的场景,我们需要在服务器上设置一组公钥和私钥,使用私钥对JWT进行签名,然后将JWT和公钥字符串返回给客户端。

客户端收到JWT后,在需要验证和解析JWT的地方,可以将公钥字符串转换成公钥,使用公钥对JWT进行验证和解析。

下面是一些基本的示例代码。

1. 生成JWT

import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtils {

    private static final String ALGORITHM = "RSA";
    private static final int KEY_SIZE = 2048;
    private static final String PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" +
            "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDR4d/SLGU8W/cO\n" +
            "kVXIGPmL+UDzpzB9BFq+vP1dUxX+l5G0kvBdzz19oIZlp1Vsmn8c/g/ap7hTfX0Z\n" +
            //省略私钥部分
            "-----END PRIVATE KEY-----";
    private static final String PUBLIC_KEY = "-----BEGIN PUBLIC KEY-----\n" +
            "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0eHf0ixlPFv3DpFVyBj5\n" +
            "i/lA86cwfQRavrz9XVMV/peRtJLwXc89faCGZadVbJp/HP4P2qe4U319GQ6N6Zg5\n" +
            //省略公钥部分
            "-----END PUBLIC KEY-----";

    public static String createToken(String userId) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("sub", userId);
        claims.put("iat", Date.from(Instant.now()));
        claims.put("exp", Date.from(Instant.now().plus(1, ChronoUnit.DAYS)));
        KeyPair keyPair = generateKeyPair();
        String privateKeyString = getPrivateKeyString(keyPair);
        return Jwts.builder()
                .setClaims(claims)
                .signWith(SignatureAlgorithm.RS256, keyPair.getPrivate())
                .compact();
    }

    private static KeyPair generateKeyPair() {
        KeyPairGenerator keyPairGenerator;
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
            keyPairGenerator.initialize(KEY_SIZE);
            return keyPairGenerator.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
    }

    private static String getPrivateKeyString(KeyPair keyPair) {
        return "-----BEGIN PRIVATE KEY-----\n" +
                Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded()) +
                "\n-----END PRIVATE KEY-----";
    }

}

此处我们使用RSA算法生成了一对公钥和私钥,并使用私钥对JWT进行签名并生成一个token。其中,私钥和公钥的字符格式是PEM格式的,需要进行解析和转换。

2. 验证和解析JWT

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class JwtUtils {

    // ...

    public static boolean verifyToken(String token) {
        try {
            PublicKey publicKey = getPublicKey();
            Jws<Claims> claimsJws = Jwts.parserBuilder()
                    .setSigningKey(publicKey)
                    .build()
                    .parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public static Claims parseToken(String token) {
        PublicKey publicKey = getPublicKey();
        return Jwts.parserBuilder()
                .setSigningKey(publicKey)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }

    private static PublicKey getPublicKey() throws Exception {
        String publicKeyString = PUBLIC_KEY
                .replace("-----BEGIN PUBLIC KEY-----", "")
                .replace("-----END PUBLIC KEY-----", "")
                .replaceAll("\\s","");
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyString);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        return keyFactory.generatePublic(keySpec);
    }

}

此处我们提供了两个方法,一个是验证token是否有效,一个是解析token中的数据(也就是头部和载荷)。在两个方法中,都使用了公钥对JWT进行验证和解析。

三、示例说明

下面是两个示例说明,分别演示了如何生成JWT和验证JWT的过程。

示例一:生成JWT

public static void main(String[] args) {
    String token = JwtUtils.createToken("123456");
    System.out.println(token);
}

运行结果:

eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxMjM0NTYiLCJpYXQiOjE2MjczNzc5MDcsImV4cCI6MTYyNzQ2NDA5N30.XB6WvHoltDH-5jwSBfLqM4-hnltwIz2LaklZVBZcDwzACVKKyw-aU2XxwkVGllCgjzDtl8JGtO0cc_Kh0xo3WMoovqW1uwYGW-p6pN1n8mU8tgyn2ob1nZyDK0VQU0_CXjHPScjRljwoeZoY1b24-ctKzZiS9rwver_3BIQf1-nCJ9g3trNvUfkc9vZeZKakHSMtr9v6JizlOp2R0-kwmM3whiiIH_QjAbYcqOyU_Vbgi7Q4y91umx4DXZS9O9vDuQ15rvvPvVOXdbEBhep83mRrvvFIwzmYLnEp5a5cyQKw6R7fWYBHHbDOhK3OqDKtEYDHb3pNtf7-Vw

生成的jwt包含了头部、载荷和签名信息,其中载荷中包含了sub、iat和exp等字段信息。这里我们使用了PEM格式的字符串描述了私钥和公钥,通过使用私钥对JWT进行签名和验证,提高了数据的安全性。

示例二:解析JWT

public static void main(String[] args) {
    String token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxMjM0NTYiLCJpYXQiOjE2MjczNzc5MDcsImV4cCI6MTYyNzQ2NDA5N30.XB6WvHoltDH-5jwSBfLqM4-hnltwIz2LaklZVBZcDwzACVKKyw-aU2XxwkVGllCgjzDtl8JGtO0cc_Kh0xo3WMoovqW1uwYGW-p6pN1n8mU8tgyn2ob1nZyDK0VQU0_CXjHPScjRljwoeZoY1b24-ctKzZiS9rwver_3BIQf1-nCJ9g3trNvUfkc9vZeZKakHSMtr9v6JizlOp2R0-kwmM3whiiIH_QjAbYcqOyU_Vbgi7Q4y91umx4DXZS9O9vDuQ15rvvPvVOXdbEBhep83mRrvvFIwzmYLnEp5a5cyQKw6R7fWYBHHbDOhK3OqDKtEYDHb3pNtf7-Vw";
    Claims claims = JwtUtils.parseToken(token);
    System.out.println(claims);
}

运行结果:

{sub=123456, iat=1627377907, exp=1627464097}

解析JWT后,我们得到了payload中携带的用户数据,包括sub、iat和exp字段,分别代表用户ID、JWT的签发时间和过期时间。这些数据可以根据业务需要进行进一步的处理。

本文链接:http://task.lmcjl.com/news/13045.html

展开阅读全文