java生成jwt并使用RSA签名

一、生成jwt

在java中生成jwt的库用得比较多的是nimbus-jose-jwt、jose4j、java-jwt 和 jjwt (已迁移为jwt-api)。这里使用nimbus-jose-jwt。

引入依赖:

implementation("com.nimbusds:nimbus-jose-jwt:9.27")

生成jwt:

// (1) 生成RSA公钥-秘钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// (2) Create RSA signer
JWSSigner signer = new RSASSASigner(keyPair.getPrivate());

// (3) 生成jws头
JWSHeader jwsHeader = new JWSHeader
  .Builder(JWSAlgorithm.RS512)    // 指定 RSA 算法
  .type(JOSEObjectType.JWT)
  .build();

// (4) 生成jws对象
JWSObject jwsObject = new JWSObject(new JWSHeader(JWSAlgorithm.RS512), new Payload(Map.of("userId", "123456")));
// (5) 给jwt签名
jwsObject.sign(signer);
// (6) 生成jwt字符串
String jwtToken = jwsObject.serialize();

(1)生成RSA公钥-秘钥对。

(2)使用RSA秘钥对创建一个jws签名对象。

(3)生成jws头,并指定签名算法JWSAlgorithm.RS512。

(4)生成jws对象,claims数据为Map.of("userId", "123456")。

(5)使用jws对象给jwt签名。

(6)生成jwt字符串。

二、解析jwt token

JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) keyPair.getPublic());(1)
JWSObject parseObj = JWSObject.parse(jwtToken);(2)
if(parseObj.verify(verifier)) {(3)
  Map<String, Object> stringObjectMap = parseObj.getPayload().toJSONObject();
  System.err.println(stringObjectMap);
}

(1)使用RSA公钥(前面步骤中生成的密钥对)创建一个验证器。

(2)解析jwt token。

(3)验证jwt签名,如果验证通过则jwt是有效的。

三、从证书生成RSA对象

1. 使用java自带的keytool工具生成证书文件
$ keytool -genkey -alias jwt-alias-name -keyalg RSA -keystore jwt.jks
2. 生成jwt
//(1) 从本地证书读取秘钥对
char[] password  = "123456".toCharArray();
FileInputStream fis = new FileInputStream("/home/jwt.jks");
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(fis, password);
Key key = keyStore.getKey("jwt-alias-name", password);
KeyPair pair = null;
if (key instanceof PrivateKey) {
  Certificate certificate = keyStore.getCertificate("jwt-alias-name");
  PublicKey publicKey = certificate.getPublicKey();
  pair = new KeyPair(publicKey, (PrivateKey)key);
}

// (2)创建RSAKey对象
RSAKey rsaKey = new RSAKey.Builder((RSAPublicKey) pair.getPublic())
  .privateKey(pair.getPrivate())
  .keyID(UUID.randomUUID().toString())
  .build();
// (3) 使用RSAKey生成JWSSigner
JWSSigner jwsSigner = new RSASSASigner(rsaKey, true);   // rsaKey 生成签名器
// 生成jwt token......

(1)从本地证书读取秘钥对。

(2)创建RSAKey对象。

(3)使用RSAKey生成JWSSigner,后续操作和之前一致。

5. 解析jwt token
String token = ...;
JWSObject jwsObject = JWSObject.parse(token);

// (1)使用签名步骤生成的RSA
RSAKey rsaKey = ...;
RSAKey publicRsaKey = rsaKey.toPublicJWK();
// (2) 使用公钥创建JWSVerifier
JWSVerifier jwsVerifier = new RSASSAVerifier(publicRsaKey);

// (3)验证签名
if (!jwsObject.verify(jwsVerifier)) {
    throw new RuntimeException("token签名不合法!");
}
Map<String, Object> claims = jwsObject.getPayload().toJSONObject();

(1)使用签名步骤生成的RSA。

(2)使用公钥创建JWSVerifier。

(3)验证签名。

四、生成jwks

// (1) 生成RSA公钥-秘钥对
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();

RSAKey rsaKey = new RSAKey.Builder((RSAPublicKey) keyPair.getPublic())
  .privateKey(keyPair.getPrivate())
  .keyID(UUID.randomUUID().toString())
  .build();
// (1)显示秘钥和公钥
System.out.println(rsaKey);
// (2)只显示公钥
System.out.println(rsaKey.toPublicJWK());

(1)显示秘钥和公钥。

(2)只显示公钥。

jwt标准格式:

// Convert to JWK format
JWK jwk = new RSAKey.Builder((RSAPublicKey)keyPair.getPublic())
  .privateKey((RSAPrivateKey)keyPair.getPrivate())
  .keyUse(KeyUse.SIGNATURE)
  .keyID(UUID.randomUUID().toString())
  .issueTime(new Date())
  .build();
// (1)显示秘钥和公钥
System.out.println(jwk);
// (2)只显示公钥
System.out.println(jwk.toPublicJWK());

(1)显示秘钥和公钥。

(2)只显示公钥。

五、从jwks生成RSAKey

RSAKey rsaKey1 = RSAKey.parse("{...}");
JWSVerifier verifier = new RSASSAVerifier(rsaKey1);

JWSObject parseObj = JWSObject.parse(jwtToken);
if(parseObj.verify(verifier)) {
  Map<String, Object> stringObjectMap = parseObj.getPayload().toJSONObject();
  System.err.println(stringObjectMap);
}

五、参考地址

[Examples](

posted @ 2023-01-05 00:42  我爱这世间美貌女子  阅读(1344)  评论(0编辑  收藏  举报