我正在使用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


当我使用相同的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解码的。

我的假设是对的。这是库中的错误,还是我弄错了?

最佳答案

使用的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编码。

10-07 16:34