为 JWT 存储 RSA256 密钥
Storing RSA256 keys for JWT
我在为 Json Web 令牌 (JWT) 存储 RSA256 私有和 public 令牌时遇到问题。
我正在使用 jsonwebtoken.io,我创建了令牌,并且能够使用已作为文本存储在我的数据库中的私钥和 public 密钥来验证令牌。
public String createJWTToken(Map<String, Object> claims) {
if (replaceAt.isBefore(Instant.now())) {
loadKeyFromStorage();
}
String jws = Jwts.builder()
.setHeaderParam(JwsHeader.KEY_ID, currentKid)
.setHeaderParam(JwsHeader.ALGORITHM, algorithm)
.setClaims(claims)
.signWith(currentPrivateKey, algorithm)
.compact();
Jws<Claims> claimsCheck = Jwts.parserBuilder().setSigningKey(currentPublicKey).build().parseClaimsJws(jws);
return jws;
}
但是,如果我将令牌带到 JWT.io 并尝试使用我的 public 密钥验证它,它会说它无效。
我的 JWT 令牌
eyJraWQiOiI1Njg3YmM0NS00ZjVlLTQ2ZDQtYTlmZi0yZjA2NjM4MWIxNjYiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJITVpTbTJjdkVMQ0dSeWJnN0JlQSIsImF1ZCI6ImJGZXdyYlBSdFl1QVQ3cjVsNWQ0IiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmFyY2hpcGVsYWdvLmJ1aWxkIiwic2NvcGVzIjoiIiwiZXhwIjoxNjE1MTc0MzgyLCJpYXQiOjE2MTI1ODIzODJ9.CKIe_kWSFGqkghqfJDIXtAqKVbrvKlMsdbeYNsl_AaoHjUmMYPqzchHPmMzVDUsDZEg8iugH6Og5nxFJBiONxr6Bt1h7J-yUF1-9DHJ2SNrtcJdWpzWrn0FUocXpTFpysxBTw9eaVc988z6XGG2MQtfJyEzLgAFJXBrPp-kM9guP8CvZhf1OuDzDGtvVl3ig2P3AQaWod6O6f-VUWDD6khmymYFikiDMk9KGW5eMmlPqJqHy3NyCO8vEDb9c0DGWkQL4dSA-gpqbzERN8303SLYI47PTbI0b-t7wxzYaCN4-GvSy8Gwp0hfN9VzFCMJ6pWc6a7HJinwNUDUWRTQ_nA
私钥
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCM7pSzSVJgZql7vAIBFsJ3k1CKr7PnsEFrn1VpdBs+Anu8wOOwJ7sKmOSwpMembh6EIU9vv4Xi5GMHQNn+y7+1p8ktFOqPYzyLWK2pISJTOMJRYbZmPZRrJLXubQntiFHqRuHkhB9VZ16Yj7Pbsy7TnHAE1ypZkwcVOxNObOiGIGwy1MD9+ayc0ciPJQXX67bsIZhPwzuY1uSfaTm1qEPqDa//LQU8TcgHoQzXjDT++n5WssI2GXX/kFDvkMaa8YibY3LHMlOHKtfnVyQ2Jh7gqsiIEzasRHOCBG3FPaGPMJH0KjElC9cfHdfRzpnRZ5AGZnpybLRNLrMjwV/7kYApAgMBAAECggEAU4oZGy2bZwlz7aTEi2CyZa8tTwhX3D7eiK0qNBhfDaLrNjggv4rNlLqM1SjYMA+Whzw3mkYtVxGKogIPNroQKd4Lom2DnPt2KCOozViWwD4k8Zi6RmC6WcipD2wTNnpYFEdwH8Uxza44pLaKJvFQEJ/qxvPEZtSAnlUmXJayPs6Xp7Pm1Pix4bp2i/Ozsd17sYv0+GFPRTf0JT3u6KhKNTERyZ9XxKwglww7LfGZQKVF0VxS/12ok7egX2LN1T8cDIo53H3oyxuFsAHQ+RcPDXrx6KRUou6a7CD+mX+WDKJOxguw90kSUBfJeb5pX6p+KgALln5onzsgycxP1E2fAQKBgQDK3ii08i/ymjRc/j6uiIYR0twe3/xymMx9vx4wc0sTolao+llvJPcNyC6poag2DV+ciCEf9EvwJBYwwEu6+4xoi+q8mnRhS5Twh9pNQeg1F4ST1JvURWX4HaCPtHImTeJ23bCymrDmW8SdT2qIATpAwCsxLs5OaEJncbAuGUQBSwKBgQCx18JNx63Yn6JSOA38zxKusyiKsxvtcC1zVg1UE2W1x4kC1hxUD7i/tamEJSW9qer4pJdMdcda74I3pppcpnq7L7Ga7YjFd93pZ9+FlzGhASz1NF/I1pxIL0boOUthBruUSOjlAVO1IYrTfNsxPvchK0Bqbv4j6A+45TkXhVMP2wKBgDwl6D3V/L9aVyInQ6Bt3ApW0WraEDhN83to+eN1m5HjtPv+1httA07zxloHEx+LkYiQl/mobgdyO54StaFnybaJnXxz8wOR7EPwk5oKa3WqVmWaSOWD+fq5lgxlfN68guOpUSVzVfXGyaG2lShj7Mib8XJwpTx8Dwwqmgjg9tfHAoGBAIBLdAKEYCd70a+afIy6HXImEMMuPqFlYYRouajDbYZbcb24FCuYQ+EY/jc0TSur3rSMmBEyjiRN0BSxfX4FI1jSKT/ox9gchtwQcTGARu8tV+90Xv0VxRxV7sMsQfK21q88gbZi5K4wimPTGJVIJSOqfgfKFlB04pKx2iPbrHYtAoGAFwyBVopeMNCbDyEtO6eDGuBAnOaG1SHy0r/K9FN007/2Ha7tXFBfAP7++3ecYcPmHswk33y1xQFcc9bIWH8m2jBdU6zhl5fi6UA9CNaxl4FBlyfNWxLjenxEYd2SWHQLzX2cBJSTM3SVZsM5h/1jk04DFGp0nwfkl8d/8/3UslE=
public键
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjO6Us0lSYGape7wCARbCd5NQiq+z57BBa59VaXQbPgJ7vMDjsCe7CpjksKTHpm4ehCFPb7+F4uRjB0DZ/su/tafJLRTqj2M8i1itqSEiUzjCUWG2Zj2UayS17m0J7YhR6kbh5IQfVWdemI+z27Mu05xwBNcqWZMHFTsTTmzohiBsMtTA/fmsnNHIjyUF1+u27CGYT8M7mNbkn2k5tahD6g2v/y0FPE3IB6EM14w0/vp+VrLCNhl1/5BQ75DGmvGIm2NyxzJThyrX51ckNiYe4KrIiBM2rERzggRtxT2hjzCR9CoxJQvXHx3X0c6Z0WeQBmZ6cmy0TS6zI8Ff+5GAKQIDAQAB
这就是我创建密钥的方式
private JWKKey createNewKey() {
KeyPair keyPair = Keys.keyPairFor(algorithm);
JWKKey key = JWKKey.builder()
.kid(UUID.randomUUID().toString())
.privateKey(Encoders.BASE64.encode(keyPair.getPrivate().getEncoded()))
.publicKey(Encoders.BASE64.encode(keyPair.getPublic().getEncoded()))
.expiresAt(Instant.now().plusSeconds(KeyLifeSpan))
.build();
dynamoDB.putItem(new PutItemRequest(keysTableName, ImmutableMap.<String, AttributeValue>builder()
.put(DBK.KID, AV.of(key.getKid()))
.put(DBK.EXPIRES, AV.of(key.getExpiresAt()))
.put(DBK.PRIVATE_KEY, AV.of(key.getPrivateKey()))
.put(DBK.PUBLIC_KEY, AV.of(key.getPublicKey()))
.build()));
return key;
}
这就是我从数据库加载密钥的方式
private void setKeyUsage(JWKKey key) {
currentKid = key.getKid();
replaceAt = key.getExpiresAt().minusSeconds(longestTokenLife);
try {
KeyFactory kf = KeyFactory.getInstance("RSA");
currentPrivateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key.getPrivateKey().getBytes(StandardCharsets.UTF_8))));
currentPublicKey = kf.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(key.getPublicKey().getBytes(StandardCharsets.UTF_8))));
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
经过几天的尝试,我发现 jwt.io 要求 public 密钥以“-----BEGIN RSA PUBLIC KEY-----”开头并结束使用“-----END RSA PUBLIC KEY-----”
我在为 Json Web 令牌 (JWT) 存储 RSA256 私有和 public 令牌时遇到问题。
我正在使用 jsonwebtoken.io,我创建了令牌,并且能够使用已作为文本存储在我的数据库中的私钥和 public 密钥来验证令牌。
public String createJWTToken(Map<String, Object> claims) {
if (replaceAt.isBefore(Instant.now())) {
loadKeyFromStorage();
}
String jws = Jwts.builder()
.setHeaderParam(JwsHeader.KEY_ID, currentKid)
.setHeaderParam(JwsHeader.ALGORITHM, algorithm)
.setClaims(claims)
.signWith(currentPrivateKey, algorithm)
.compact();
Jws<Claims> claimsCheck = Jwts.parserBuilder().setSigningKey(currentPublicKey).build().parseClaimsJws(jws);
return jws;
}
但是,如果我将令牌带到 JWT.io 并尝试使用我的 public 密钥验证它,它会说它无效。 我的 JWT 令牌
eyJraWQiOiI1Njg3YmM0NS00ZjVlLTQ2ZDQtYTlmZi0yZjA2NjM4MWIxNjYiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJITVpTbTJjdkVMQ0dSeWJnN0JlQSIsImF1ZCI6ImJGZXdyYlBSdFl1QVQ3cjVsNWQ0IiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmFyY2hpcGVsYWdvLmJ1aWxkIiwic2NvcGVzIjoiIiwiZXhwIjoxNjE1MTc0MzgyLCJpYXQiOjE2MTI1ODIzODJ9.CKIe_kWSFGqkghqfJDIXtAqKVbrvKlMsdbeYNsl_AaoHjUmMYPqzchHPmMzVDUsDZEg8iugH6Og5nxFJBiONxr6Bt1h7J-yUF1-9DHJ2SNrtcJdWpzWrn0FUocXpTFpysxBTw9eaVc988z6XGG2MQtfJyEzLgAFJXBrPp-kM9guP8CvZhf1OuDzDGtvVl3ig2P3AQaWod6O6f-VUWDD6khmymYFikiDMk9KGW5eMmlPqJqHy3NyCO8vEDb9c0DGWkQL4dSA-gpqbzERN8303SLYI47PTbI0b-t7wxzYaCN4-GvSy8Gwp0hfN9VzFCMJ6pWc6a7HJinwNUDUWRTQ_nA
私钥
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCM7pSzSVJgZql7vAIBFsJ3k1CKr7PnsEFrn1VpdBs+Anu8wOOwJ7sKmOSwpMembh6EIU9vv4Xi5GMHQNn+y7+1p8ktFOqPYzyLWK2pISJTOMJRYbZmPZRrJLXubQntiFHqRuHkhB9VZ16Yj7Pbsy7TnHAE1ypZkwcVOxNObOiGIGwy1MD9+ayc0ciPJQXX67bsIZhPwzuY1uSfaTm1qEPqDa//LQU8TcgHoQzXjDT++n5WssI2GXX/kFDvkMaa8YibY3LHMlOHKtfnVyQ2Jh7gqsiIEzasRHOCBG3FPaGPMJH0KjElC9cfHdfRzpnRZ5AGZnpybLRNLrMjwV/7kYApAgMBAAECggEAU4oZGy2bZwlz7aTEi2CyZa8tTwhX3D7eiK0qNBhfDaLrNjggv4rNlLqM1SjYMA+Whzw3mkYtVxGKogIPNroQKd4Lom2DnPt2KCOozViWwD4k8Zi6RmC6WcipD2wTNnpYFEdwH8Uxza44pLaKJvFQEJ/qxvPEZtSAnlUmXJayPs6Xp7Pm1Pix4bp2i/Ozsd17sYv0+GFPRTf0JT3u6KhKNTERyZ9XxKwglww7LfGZQKVF0VxS/12ok7egX2LN1T8cDIo53H3oyxuFsAHQ+RcPDXrx6KRUou6a7CD+mX+WDKJOxguw90kSUBfJeb5pX6p+KgALln5onzsgycxP1E2fAQKBgQDK3ii08i/ymjRc/j6uiIYR0twe3/xymMx9vx4wc0sTolao+llvJPcNyC6poag2DV+ciCEf9EvwJBYwwEu6+4xoi+q8mnRhS5Twh9pNQeg1F4ST1JvURWX4HaCPtHImTeJ23bCymrDmW8SdT2qIATpAwCsxLs5OaEJncbAuGUQBSwKBgQCx18JNx63Yn6JSOA38zxKusyiKsxvtcC1zVg1UE2W1x4kC1hxUD7i/tamEJSW9qer4pJdMdcda74I3pppcpnq7L7Ga7YjFd93pZ9+FlzGhASz1NF/I1pxIL0boOUthBruUSOjlAVO1IYrTfNsxPvchK0Bqbv4j6A+45TkXhVMP2wKBgDwl6D3V/L9aVyInQ6Bt3ApW0WraEDhN83to+eN1m5HjtPv+1httA07zxloHEx+LkYiQl/mobgdyO54StaFnybaJnXxz8wOR7EPwk5oKa3WqVmWaSOWD+fq5lgxlfN68guOpUSVzVfXGyaG2lShj7Mib8XJwpTx8Dwwqmgjg9tfHAoGBAIBLdAKEYCd70a+afIy6HXImEMMuPqFlYYRouajDbYZbcb24FCuYQ+EY/jc0TSur3rSMmBEyjiRN0BSxfX4FI1jSKT/ox9gchtwQcTGARu8tV+90Xv0VxRxV7sMsQfK21q88gbZi5K4wimPTGJVIJSOqfgfKFlB04pKx2iPbrHYtAoGAFwyBVopeMNCbDyEtO6eDGuBAnOaG1SHy0r/K9FN007/2Ha7tXFBfAP7++3ecYcPmHswk33y1xQFcc9bIWH8m2jBdU6zhl5fi6UA9CNaxl4FBlyfNWxLjenxEYd2SWHQLzX2cBJSTM3SVZsM5h/1jk04DFGp0nwfkl8d/8/3UslE=
public键
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjO6Us0lSYGape7wCARbCd5NQiq+z57BBa59VaXQbPgJ7vMDjsCe7CpjksKTHpm4ehCFPb7+F4uRjB0DZ/su/tafJLRTqj2M8i1itqSEiUzjCUWG2Zj2UayS17m0J7YhR6kbh5IQfVWdemI+z27Mu05xwBNcqWZMHFTsTTmzohiBsMtTA/fmsnNHIjyUF1+u27CGYT8M7mNbkn2k5tahD6g2v/y0FPE3IB6EM14w0/vp+VrLCNhl1/5BQ75DGmvGIm2NyxzJThyrX51ckNiYe4KrIiBM2rERzggRtxT2hjzCR9CoxJQvXHx3X0c6Z0WeQBmZ6cmy0TS6zI8Ff+5GAKQIDAQAB
这就是我创建密钥的方式
private JWKKey createNewKey() {
KeyPair keyPair = Keys.keyPairFor(algorithm);
JWKKey key = JWKKey.builder()
.kid(UUID.randomUUID().toString())
.privateKey(Encoders.BASE64.encode(keyPair.getPrivate().getEncoded()))
.publicKey(Encoders.BASE64.encode(keyPair.getPublic().getEncoded()))
.expiresAt(Instant.now().plusSeconds(KeyLifeSpan))
.build();
dynamoDB.putItem(new PutItemRequest(keysTableName, ImmutableMap.<String, AttributeValue>builder()
.put(DBK.KID, AV.of(key.getKid()))
.put(DBK.EXPIRES, AV.of(key.getExpiresAt()))
.put(DBK.PRIVATE_KEY, AV.of(key.getPrivateKey()))
.put(DBK.PUBLIC_KEY, AV.of(key.getPublicKey()))
.build()));
return key;
}
这就是我从数据库加载密钥的方式
private void setKeyUsage(JWKKey key) {
currentKid = key.getKid();
replaceAt = key.getExpiresAt().minusSeconds(longestTokenLife);
try {
KeyFactory kf = KeyFactory.getInstance("RSA");
currentPrivateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key.getPrivateKey().getBytes(StandardCharsets.UTF_8))));
currentPublicKey = kf.generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode(key.getPublicKey().getBytes(StandardCharsets.UTF_8))));
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new RuntimeException(e);
}
}
经过几天的尝试,我发现 jwt.io 要求 public 密钥以“-----BEGIN RSA PUBLIC KEY-----”开头并结束使用“-----END RSA PUBLIC KEY-----”