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](