使用 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 令牌有效

JWT 身份验证方案中的刷新令牌是不是应该使用与访问令牌不同的秘密进行签名?

验证 JWT 令牌签名

JWT 签名验证

无法验证从 Azure AD 获得的访问令牌签名以保护 Web API