web-dev-qa-db-fra.com

La signature JWT ne correspond pas à la signature calculée localement

J'utilise

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

pour créer un jeton puis

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

pour authentifier. Lorsque je lance cela dans un test JUnit, cela fonctionne très bien. Cependant, lorsque j'authentifie le jeton passé en tant qu'en-tête sur REST, l'authentification échoue avec SignatureException. J'ai vérifié le jeton aux deux extrémités de l'appel HTTP et la chaîne de jeton est identique. Code à créer/authenticate est statique, donc le secret est le même de chaque côté.

9
stanlick

static Key secret = MacProvider.generateKey(); générera une nouvelle clé aléatoire à chaque rechargement de votre serveur car les variables statiques sont initialisées lors du chargement de la classe

Cela signifie que si vous émettez un JWT, il n'est valide que tant que le serveur ne redémarre pas. Le SignatureException que vous avez est dû au fait que la clé de signature est différente

Vous devez stocker la clé de signature secret.getEncoded() après la première génération et la charger au démarrage de votre module

9
pedrofb

J'avais un problème similaire. Dans mon cas, c'était une mauvaise validation de jeton. Je mets le signe en octets:

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

Mais lorsque j'analysais le jeton et définissais signKey, je le définissais comme une chaîne, pas comme des octets:

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

Vérifiez également toujours les guillemets et les espaces lors de la vérification du jeton, il peut souvent y avoir un espace/devis excédentaire au début/à la fin du jeton (utilisez la méthode trim ())

2
S.Dayneko

J'avais un problème similaire. Dans mon cas, les deux clés étaient identiques, mais pour une raison quelconque, je recevais un jeton entre guillemets (par exemple "Syasda.da3das.aDjty6" au lieu de simplement Syasda.da3das.aDjty6).

Cela m'a pris tellement de temps pour réaliser cela car la plupart du temps lors des tests sur jwt.io, je copiais simplement le jeton manuellement sans les crochets pour le vérifier.

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

La suppression de ces citations a résolu le problème pour moi. J'espère que cela aidera aussi quelqu'un d'autre.

1
Nuper

J'ai eu le même problème, j'ai remarqué que dans les sources chaque fois qu'ils convertissent la clé de signature, ils spécifient explicitement l'encodage UTF-8. J'ai essayé de changer l'encodage tout en décodant le jeton:

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

Et lors de la signature du 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();
    }

C'est la seule chose qui a corrigé cela pour moi.

1
Dmytro Kostyushko

J'ai résolu le problème de modification de l'hôte dans l'URL REST endpoint. Il y avait un mauvais hôte qui a renvoyé l'erreur HTTP 401 non autorisé.

0
jis83