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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/42397484/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 00:07:49  来源:igfitidea点击:

JWT signature does not match locally computed signature

javajwttoken

提问by stanlick

I am using

我在用

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

to create a token then

然后创建一个令牌

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

to authenticate. When I run this in a JUnit test, it works fine. However, when I authenticate token passed as a header over REST call, authentication fails with SignatureException. I have verified the token on both ends of the HTTP call and the token string is identical. Code to create/authenticate is static, therefore, the secret is same on each side.

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

采纳答案by pedrofb

static Key secret = MacProvider.generateKey();will generate a new random key each time your server is reloaded because static variables are initialized when the class is loaded

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

It means that if you issue a JWT, it is only valid as long as the server does not reboot. The SignatureExceptionyou got is because the signing key it is different

这意味着如果您发出 JWT,它仅在服务器不重启时有效。在SignatureException你得到的是因为签名密钥是不同的

You need to store the signing key secret.getEncoded()after first generation and load it when your module starts

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

回答by Nuper

I had a similar problem. In my case both keys where the same, but for some reason I was receiving a token within quotes (e.g "Syasda.da3das.aDjty6"instead of just Syasda.da3das.aDjty6).

我有一个类似的问题。在我的情况下,两个键相同,但出于某种原因,我收到了引号内的标记(例如,"Syasda.da3das.aDjty6"而不是仅Syasda.da3das.aDjty6)。

It took me so much time to realize this since most of the time while testing on jwt.io I would just copy the token manually without the brackets to verify it.

我花了很多时间才意识到这一点,因为大部分时间在 jwt.io 上进行测试时,我只会手动复制令牌而不用括号来验证它。

token = token.replace("\"",""); 

Removing those quotes solved the problem for me. Hopefully this will help someone else as well.

删除这些引号为我解决了问题。希望这也能帮助其他人。

回答by S.Dayneko

I had a similar problem. In my case it was wrong token validation. I set sign as bytes:

我有一个类似的问题。就我而言,这是错误的令牌验证。我将符号设置为字节:

.signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret().getBytes())

But when i was parsing the token and setting signKey i setted it as a String, not as bytes:

但是当我解析令牌并设置 signKey 时,我将其设置为字符串,而不是字节:

Jwts.parser().setSigningKey(signingKey).parseClaimsJws(this.token)

Also always check quotes and spaces when checking token, there often can be excess space/quote in the start/end of the token (use trim() method)

在检查标记时也总是检查引号和空格,在标记的开始/结束处经常会有多余的空格/引号(使用 trim() 方法)

回答by Dmytro Kostyushko

I have had the same problem, I noticed that in sources whenever they convert the signing key they explicitly specify UTF-8 encoding. I tried changing the encoding while both decoding the token:

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

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

And when signing the 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();
    }

This is the only thing that fixed this for me.

这是唯一为我解决这个问题的东西。

回答by jis83

I solved the problem modifying the HOST in the URL REST endpoint. It had a wrong host which was returned error HTTP 401 unauthorized.

我解决了修改 URL REST 端点中的 HOST 的问题。它有一个错误的主机,返回错误 HTTP 401 未经授权。

回答by Arrow.Tao

Two types of problems meight exists:

可能存在两种类型的问题:

  1. Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);generates a different random key each time the function secretKeyForis run. So if you want to generate a constant key, try this one
  1. Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);每次运行该函数时secretKeyFor都会生成不同的随机密钥。所以如果你想生成一个常量键,试试这个
 public SecretKey generalKey(){
        String stringKey = Global.JWT_SECRET;
        byte[] encodedKey =Base64.decodeBase64(stringKey);
        SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length,
                "HmacSHA512");
        return key;
    }
  1. In my code, I recieve the token transferred by ajax, and JSON.stringify() is used to convert the javasript object to string, which wrapped additional quota on the origin string, try to eliminate the quota as Nupersaid.
  1. 在我的代码中,我收到了ajax传输的token,JSON.stringify()用于将javasript对象转换为字符串,在原始字符串上包装了额外的配额,尝试消除Nuper所说的配额。