我正在使用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解码。
我的假设是正确的。这是库中的错误还是我出错?
答案 0 :(得分:1)
正在使用的JWTVerifier
版本假定您传递的密码是Base64url编码,因此在使用它之前会自动对其进行解码作为验证签名的密钥。
鉴于sfnd984f94j3fjn
是实际的秘密而您的JWTVerifier
版本会自动解码您传递的任何内容,您需要在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编码。