使用 java-jwt 验证访问令牌签名
Posted
技术标签:
【中文标题】使用 java-jwt 验证访问令牌签名【英文标题】:Verify Access token signature using java-jwt 【发布时间】:2021-11-16 02:35:43 【问题描述】:我正在尝试验证由 KeyCloak 授权服务器生成的 JWT 访问令牌。
我已经从 http://ip-address:port/auth/realms/
为了验证访问令牌,我使用https://mvnrepository.com/artifact/com.auth0/java-jwt
并参考https://www.baeldung.com/java-jwt-token-decode 验证签名。
我正在尝试的代码:
String publicKey =<public_key from http://<ip>:<port>/auth/realms/<app> >
String accessToken =<valid access token from keycloak>
String[] chunks = accessToken.split("\\.");
Base64.Decoder decoder = Base64.getDecoder();
String header = new String(decoder.decode(chunks[0])); // "alg":"RS256","typ" : "JWT","kid" : "dsssdssdf"
String payload = new String(decoder.decode(chunks[1])); //"exp":1632237161,"iat":1632236861,"auth_time":1632236854,"jt..."
String signature = chunks[2]; // <signature from access token>
SignatureAlgorithm sa = SignatureAlgorithm.RS256;
String tokenWithoutSignature = chunks[0] + "." + chunks[1];
SecretKeySpec secretKeySpec = new SecretKeySpec(publicKey.getBytes(), sa.getJcaName());
DefaultJwtSignatureValidator validator = new DefaultJwtSignatureValidator(sa, secretKeySpec);
if (!validator.isValid(tokenWithoutSignature, signature))
System.out.println("=============== Invalid access token");
else
System.out.println("============= valid access token");
运行上述代码后观察到以下错误:
java.lang.IllegalArgumentException: RSA Signature validation requires either a RSAPublicKey or RSAPrivateKey instance.
at io.jsonwebtoken.lang.Assert.isTrue(Assert.java:38)
at io.jsonwebtoken.impl.crypto.RsaSignatureValidator.<init>(RsaSignatureValidator.java:36)
at io.jsonwebtoken.impl.crypto.DefaultSignatureValidatorFactory.createSignatureValidator(DefaultSignatureValidatorFactory.java:43)
at io.jsonwebtoken.impl.crypto.DefaultJwtSignatureValidator.<init>(DefaultJwtSignatureValidator.java:37)
at io.jsonwebtoken.impl.crypto.DefaultJwtSignatureValidator.<init>(DefaultJwtSignatureValidator.java:32)
有人可以帮忙吗?
【问题讨论】:
【参考方案1】:我尝试类似:
String publicKey =<public_key from http://<ip>:<port>/auth/realms/<app> >
byte[] decoded = Base64.getDecoder().decode(publicKey);
String algorithm = "RSA";
KeyFactory kf = KeyFactory.getInstance(algorithm);
PublicKey generatedPublic = kf.generatePublic(new X509EncodedKeySpec(decoded));
String accessToken =<valid access token from keycloak>
String[] chunks = accessToken.split("\\.");
Base64.Decoder decoder = Base64.getDecoder();
String header = new String(decoder.decode(chunks[0])); // "alg":"RS256","typ" : "JWT","kid" : "dsssdssdf"
String payload = new String(decoder.decode(chunks[1])); //"exp":1632237161,"iat":1632236861,"auth_time":1632236854,"jt..."
String signature = chunks[2]; // <signature from access token>
SignatureAlgorithm sa = SignatureAlgorithm.RS256;
String tokenWithoutSignature = chunks[0] + "." + chunks[1];
DefaultJwtSignatureValidator validator = new DefaultJwtSignatureValidator(sa, generatedPublic);
if (!validator.isValid(tokenWithoutSignature, signature))
System.out.println("=============== Invalid access token");
else
System.out.println("============= valid access token");
而且成功了!!
【讨论】:
以上是关于使用 java-jwt 验证访问令牌签名的主要内容,如果未能解决你的问题,请参考以下文章
无法验证 AAD 访问令牌 - IDX10511:签名验证失败
验证 Azure 广告访问令牌时签名无效,但 id 令牌有效