Auth0 java-jwt 库无法验证有效令牌

Posted

技术标签:

【中文标题】Auth0 java-jwt 库无法验证有效令牌【英文标题】:Auth0 java-jwt library fails to verify a valid token 【发布时间】:2017-04-05 12:30:56 【问题描述】:

我正在使用 Auth0 java-jwt 库来生成 JWT 令牌,但是,一旦生成,我就无法验证令牌。

这是我用来生成令牌的代码:

final JWTSigner signer = new JWTSigner(secret);
final HashMap<String, Object> claims = new HashMap<String, Object>();
claims.put("user", user);
claims.put("email", user.getEmail());
final String jwt = signer.sign(claims);
return jwt;

这是我的秘密和令牌(它在https://jwt.io/ 中验证正确):

秘密: sfnd984f94j3fjn

令牌强>:eyJ0eXBlIjoiSldUIiwiYWxnIjoiSFMyNTYifQ.eyJ1c2VyIjp7ImlkIjoyLCJlbWFpbCI6InNhbnRob3NoQHh5ei5jb20iLCJwYXNzd29yZCI6IiQyYSQxMCRHSlNNRGtRRUEvRVNsRENJcVlud0R1Ly45YWRqRWRQalVvSWVKUmlsSmpSeHh6N2s2Q01xQyIsImZpcnN0X25hbWUiOiJzYW50aG9zaCIsImxhc3RfbmFtZSI6Imt1bWFyIiwic3RhdHVzIjoxLCJ0aXRsZSI6IkFzc29jIiwicm9sZXMiOlt7ImlkIjoxLCJyb2xlIjoiVVNFUiJ9XX0sImVtYWlsIjoic2FudGhvc2hAeHl6LmNvbSJ9.0SHNCgUWOijpYv7xcNoPiCwg_OFZQnsdi5l7YhCsSjU P>

当我使用相同的 JWT 令牌使用 Auth0 方法对其进行验证时,它会失败(总是以签名异常结束):

try            
    final JWTVerifier verifier = new JWTVerifier(secret);
    final Map<String, Object> claims= verifier.verify(jwt);
    final String email = (String)claims.get("email");
    user =  userService.loadUserByEmail(email);
 catch (UsernameNotFoundException e) 
    // Invalid Token
 catch (SignatureException e) 
    System.out.println(e.toString());
 catch (IOException e)  
 catch (Exception e)  

我调试了库,我认为这就是问题所在(在JWTVerifier 类中):

void verifySignature(String[] pieces, String algorithm) 
    throws NoSuchAlgorithmException, InvalidKeyException, SignatureException 

    Mac hmac = Mac.getInstance(algorithm);
    hmac.init(new SecretKeySpec(decoder.decodeBase64(secret), algorithm));
    byte[] sig = hmac.doFinal(
        new StringBuilder(pieces[0]).append(".").append(pieces[1]).toString().getBytes());

    if (!Arrays.equals(sig, decoder.decodeBase64(pieces[2]))) 
        throw new SignatureException("signature verification failed");
    

这在我看来是错误的,因为 pieces[1]pieces[0] 是用 hmac.doFinal 解码的,而 pieces[2] 只是简单的 base64 解码。

我的假设是否正确。这是库中的错误还是我有什么问题?

【问题讨论】:

【参考方案1】:

正在使用的JWTVerifier 版本假定您传递的秘密是 Base64url 编码的,因此它会在使用它之前自动对其进行解码作为验证签名的密钥。

鉴于sfnd984f94j3fjn 是实际秘密,并且您的JWTVerifier 版本会自动对您传递的任何内容进行Base64url 解码,您需要在Base64url 中编码sfnd984f94j3fjn 并将编码后的版本传递给JWTVerifier.

类似的东西:

import org.apache.commons.codec.binary.Base64;

// ...

Base64 encoder = new Base64(true);

encoder.encodeBase64("sfnd984f94j3fjn".getBytes());

您可以在您正在使用的JWTVerifier 类版本的以下行中看到秘密的自动解码:

hmac.init(new SecretKeySpec(decoder.decodeBase64(secret), algorithm));

对此的更新,该库的最新版本似乎没有采用 Base64url 编码。

【讨论】:

他们应该更新他们的文档。它不明显。谢谢。 根据this commit,secrets 不再假定为 Base64,因此您使用的版本可能与在线文档不匹配。

以上是关于Auth0 java-jwt 库无法验证有效令牌的主要内容,如果未能解决你的问题,请参考以下文章

与 parse-server 和 auth0 的自定义身份验证集成

JWT 发出相同的令牌

Auth0 - 在 Owin 上使用带有承载访问令牌的 JWT 使用 RS256 进行身份验证

如何生成用于 com.auth0 java-jwt 的 RSA 密钥?

有没有办法在同一个项目中同时使用 auth0-spring-security-api 和 java-jwt?

GraphQL graph.cool 用户查询不适用于 Auth0 令牌