JWT 签名与本地计算的签名不匹配

2022-09-02 19:46:00

我正在使用

JwtBuilder builder = Jwts.builder()
                    .setId(user.getEmail())
                    .signWith(signatureAlgorithm, signingKey);

创建令牌,然后

Jwts.parser().setSigningKey(secret).parse(token);

进行身份验证。当我在JUnit测试中运行它时,它工作正常。但是,当我对作为标头通过 REST 调用传递的令牌进行身份验证时,使用 SignatureException 进行身份验证失败。我已经在HTTP调用的两端验证了令牌,并且令牌字符串是相同的。用于创建/身份验证的代码是静态的,因此,每一端的密钥都是相同的。


答案 1

static Key secret = MacProvider.generateKey();每次重新加载服务器时都会生成一个新的随机键,因为在加载类时会初始化静态变量

这意味着,如果您发出 JWT,则只要服务器不重新启动,它才有效。你得到的是因为签名密钥它是不同的SignatureException

您需要在第一代之后存储签名密钥,并在模块启动时加载它secret.getEncoded()


答案 2

我遇到了同样的问题,我注意到在源中,每当它们转换签名密钥时,它们都会显式指定UTF-8编码。我尝试在解码令牌时更改编码:

 private Jws<Claims> decodeToken(String token) {
        return Jwts.parser()
                .setSigningKey(securityProperties.getTokenSecret().getBytes(Charset.forName("UTF-8")))
                .parseClaimsJws(token);
 }

在对令牌进行签名时:

private String getSignedToken(UserDetailsAdapter user, List<String> roles, byte[] signingKey) {
        return Jwts.builder()
                .signWith(Keys.hmacShaKeyFor(signingKey), SignatureAlgorithm.HS512)
                .setHeaderParam("typ", securityProperties.getTokenType())
                .setIssuer(guiServerSecurityProperties.getTokenIssuer())
                .setAudience(guiServerSecurityProperties.getTokenAudience())
                .setSubject(user.getUsername())
                .setExpiration(new Date(System.currentTimeMillis() + 864000000))
                .claim("rol", roles)
                .compact();
    }

这是为我解决这个问题的唯一方法。