如何在 Nimbus JOSE + JWT 中验证令牌签名

Posted

技术标签:

【中文标题】如何在 Nimbus JOSE + JWT 中验证令牌签名【英文标题】:How to verify token signature in Nimbus JOSE + JWT 【发布时间】:2016-06-10 16:29:20 【问题描述】:

每次使用Nimbus JOSE + JWT 请求资源时,我都有从服务器到客户端来回传输的令牌

创建 JWT 令牌的代码:

public class TokenProvider 

    String token = "";

    public String getToken(String email) 
        try 
            KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
            keyGenerator.initialize(1024);

            KeyPair kp = keyGenerator.genKeyPair();
            RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
            RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();

            System.out.println("publicKey: " + publicKey);
            System.out.println("privateKey: " + privateKey.toString());

            JWSSigner signer = new RSASSASigner(privateKey);

            JWTClaimsSet claimsSet = new JWTClaimsSet();
            claimsSet.setSubject("RTH");
            claimsSet.setCustomClaim("email", email);
            claimsSet.setCustomClaim("role", "USER");
            claimsSet.setIssuer("https://rth.com");
            claimsSet.setExpirationTime(new Date(new Date().getTime() + 60 * 1000));

            SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256), claimsSet);

            signedJWT.sign(signer);
            token = signedJWT.serialize();
            TokenSaverAndValidatorDAO tokenSaver = new TokenSaverAndValidatorDAO();
            tokenSaver.saveTokenToDB(email, token);

            signedJWT = SignedJWT.parse(token);

            JWSVerifier verifier = new RSASSAVerifier(publicKey);
            System.out.println("verifier: " + verifier);
            System.out.println("verify method: " + signedJWT.verify(verifier));
            assertTrue(signedJWT.verify(verifier));
            assertEquals("RTH", signedJWT.getJWTClaimsSet().getSubject());
            assertEquals("https://rth.com", signedJWT.getJWTClaimsSet().getIssuer());
            assertTrue(new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime()));
         catch (JOSEException | ParseException | NoSuchAlgorithmException ex) 
            Logger.getLogger(TokenProvider.class.getName()).log(Level.SEVERE, null, ex);
        
        return token;
    

到目前为止它工作正常,但问题是我如何验证从客户端收到的令牌签名?

从API 来看,只有一种方法看起来像是用于验证,但它只接受公钥 (RSAPublicKey) 作为参数而不是令牌。

请帮助任何使用此库从事 JWT 工作的人。谢谢

【问题讨论】:

【参考方案1】:

sample code 可以执行此操作,但您的问题中已准备好执行此操作的所有代码。

对于共享密钥:

JWSVerifier verifier = new MACVerifier(sharedKey.getBytes());

如果您使用的是 RSA 密钥对(如您的示例中所示),则只需提供公钥:

JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);

然后要求它验证签名,注意如果签名无效会抛出异常:

boolean verifiedSignature = false;

    try 
      JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
      verifiedSignature = signedJWT.verify(verifier);
    
    catch (JOSEException e) 
      System.err.println("Couldn't verify signature: " + e.getMessage());
    

检查令牌签名的完整方法可能如下所示:

public static boolean isSignatureValid(String token) 
    // Parse the JWS and verify its RSA signature
    SignedJWT signedJWT;
    try 
        signedJWT = SignedJWT.parse(token);
        JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey) publicKey);
        return signedJWT.verify(verifier);
     catch (ParseException | JOSEException e) 
        return false;
    

【讨论】:

以上是关于如何在 Nimbus JOSE + JWT 中验证令牌签名的主要内容,如果未能解决你的问题,请参考以下文章

在 nimbus-jose-jwt 中,lifespan 和 refreshTime 有啥区别?

嵌套 json JWT nimbus-jose -jwt 库

无法解析 nimbus-jose-jwt 库中的符号“加密”

Nimbus JOSE JWT 加密与 RSA、私钥和公钥

编码实战2022年还在用jjwt操作jwt?,推荐你使用nimbus-jose-jwt,爽到飞起~

使用 nimbus-jose-jwt 时,当请求远程 url 进行缓存更新等时,我可以使用 RemoteJWKSet 找到(参见日志)