2017-01-15 2 views
4

Ich bin auf der Suche nach JWT in meiner Anwendung für das ich mache einige R & D darauf, indem Sie eine Referenz von: https://stormpath.com/blog/jwt-java-create-verify. Ich war erfolgreich in der Lage, die generateToken() Methode zu implementieren, wenn ich versuche verifyToken() durch Extrahieren von Anspruchssätzen. Ich verstehe nicht, woher apiKey.getSecret() stammt. Könnten Sie mir bitte dabei helfen?java.lang.IllegalArgumentException: Ein Signierschlüssel muss angegeben werden, wenn der angegebene JWT digital signiert ist

Der folgende Code als Referenz:

public class JJWTDemo { 

    private static final String secret = "MySecrete"; 

    private static String generateToken(){ 
     String id = UUID.randomUUID().toString().replace("-", ""); 
     Date now = new Date(); 
     Date exp = new Date(System.currentTimeMillis() + (1000*30)); // 30 seconds 

     String token = Jwts.builder() 
       .setId(id) 
       .setIssuedAt(now) 
       .setNotBefore(now) 
       .setExpiration(exp) 
       .signWith(SignatureAlgorithm.HS256, secret) 
       .compact(); 

     return token; 
    } 

    private static void verifyToken(String token){ 
     Claims claims = Jwts.parser(). 
       setSigningKey(DatatypeConverter.parseBase64Binary(apiKey.getSecret())) 
       .parseClaimsJws(token).getBody(); 
     System.out.println("----------------------------"); 
     System.out.println("ID: " + claims.getId()); 
     System.out.println("Subject: " + claims.getSubject()); 
     System.out.println("Issuer: " + claims.getIssuer()); 
     System.out.println("Expiration: " + claims.getExpiration()); 
    } 

    public static void main(String[] args) { 
     System.out.println(generateToken()); 
     String token = generateToken(); 
     verifyToken(token); 
    } 
} 

ich die folgenden Fehler sehen kommt:

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4N2E5NmYwNTcyN2M0ZDY0YjZmODlhNDAyOTQ2OTZiNyIsImlhdCI6MTQ4NDQ4NjYyNiwibmJmIjoxNDg0NDg2NjI2LCJleHAiOjE0ODQ0ODY2NTZ9.ycS7nLWnPpe28DM7CcQYBswOmMUhBd3wQwfZ9C-yQYs 
Exception in thread "main" java.lang.IllegalArgumentException: A signing key must be specified if the specified JWT is digitally signed. 
    at io.jsonwebtoken.lang.Assert.notNull(Assert.java:85) 
    at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:331) 
    at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:481) 
    at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:541) 
    at io.jsonwebtoken.jjwtfun.service.JJWTDemo.verifyToken(JJWTDemo.java:31) 
    at io.jsonwebtoken.jjwtfun.service.JJWTDemo.main(JJWTDemo.java:41) 

Maven Abhängigkeit:

<dependency> 
      <groupId>io.jsonwebtoken</groupId> 
      <artifactId>jjwt</artifactId> 
      <version>${jjwt.version}</version> 
     </dependency> 
<jjwt.version>0.7.0</jjwt.version> 

Antwort

5

apiKey.getSecret() in dem Blog-Artikel ist eine Referenz zu dem sicheren, zufällig generierten & Base64-kodierten geheimen Schlüssel (li ke ein Passwort), das dem API-Schlüssel zugewiesen wird, den Stormpath jedem Kunden zur Verfügung stellt. Stormpath-Kunden verwenden diesen API-Schlüssel, um jede Anforderung in der Stormpath-REST-API zu authentifizieren. Da jeder Stormpath-Kunde über einen API-Schlüssel verfügt (und der Schlüssel für Ihre Anwendung zugänglich ist), ist das API-Schlüsselgeheimnis ein idealer "Standard" zum Signieren und Verifizieren von JWTs, die für Ihre Anwendung spezifisch sind.

Wenn Sie keinen Stormpath-API-Schlüssel haben, ist ein ausreichend starkes Byte-Array mit sicherer Zufallszahl für das Signieren und Verifizieren von JWTs in Ordnung.

private static final String secret = "MySecrete"; 

ein gültiger (JWT-konform) Schlüssel, und es kann nicht für JWT HMAC Algorithmen Dies ist nicht verwendet werden:

In Ihrem obigen Beispiel wird die folgende als Testtaste.

Der JWT RFC erfordert, dass Sie MUST eine Byte-Array-Schlüssellänge gleich oder größer als die Hash-Ausgabelänge verwenden.

Das heißt, wenn Sie HS256, HS384 oder HS512 verwenden, müssen Ihre Key-Byte-Arrays 256 Bit (32 Byte), 384 Bit (48 Byte) bzw. 512 Bit (64 Byte) sein. Ich gehe darauf näher in another StackOverflow answer - sehen Sie die Daten dort, und die MacProvider Beispiele, die Sie generieren können, eine Spezifikation-konforme und sichere Schlüssel.

auf dieser Grundlage ist hier, dass Codebeispiel, um einen neu geschrieben) einen gültigen Schlüssel erzeugen und b) Bezug, dass Schlüssel als Base64-codierten String:

import io.jsonwebtoken.Claims; 
import io.jsonwebtoken.Jwts; 
import io.jsonwebtoken.SignatureAlgorithm; 
import io.jsonwebtoken.impl.crypto.MacProvider; 

import java.security.Key; 
import java.util.Base64; 
import java.util.Date; 
import java.util.UUID; 

public class JJWTDemo { 

    private static final Key secret = MacProvider.generateKey(SignatureAlgorithm.HS256); 
    private static final byte[] secretBytes = secret.getEncoded(); 
    private static final String base64SecretBytes = Base64.getEncoder().encodeToString(secretBytes); 

    private static String generateToken() { 
     String id = UUID.randomUUID().toString().replace("-", ""); 
     Date now = new Date(); 
     Date exp = new Date(System.currentTimeMillis() + (1000 * 30)); // 30 seconds 

     String token = Jwts.builder() 
      .setId(id) 
      .setIssuedAt(now) 
      .setNotBefore(now) 
      .setExpiration(exp) 
      .signWith(SignatureAlgorithm.HS256, base64SecretBytes) 
      .compact(); 

     return token; 
    } 

    private static void verifyToken(String token) { 
     Claims claims = Jwts.parser() 
      .setSigningKey(base64SecretBytes) 
      .parseClaimsJws(token).getBody(); 
     System.out.println("----------------------------"); 
     System.out.println("ID: " + claims.getId()); 
     System.out.println("Subject: " + claims.getSubject()); 
     System.out.println("Issuer: " + claims.getIssuer()); 
     System.out.println("Expiration: " + claims.getExpiration()); 
    } 

    public static void main(String[] args) { 
     System.out.println(generateToken()); 
     String token = generateToken(); 
     verifyToken(token); 
    } 
} 

anzumerken, dass Base64-kodiert Byte-Arrays ist nicht verschlüsselt (Text-Codierung! = Verschlüsselung), so stellen Sie sicher, dass, wenn Sie Base64-codieren Sie Ihre geheimen Schlüssel Bytes, die Sie immer noch diese Base64-Zeichenfolge sicher/versteckt.

Schließlich wurde der oben static final Konstanten (benannt secret, secretBytes und base64SecretBytes) gibt es für diese einfache Test Demonstration nur - man sollte nie hart Code-Schlüssel in dem Quellcode, geschweige denn sie statische Konstanten machen, da sie leicht sein kann dekompiliert.

0

Ich bin zu 100% mit Les Hazlewood einverstanden.Aber wir sollten immer die Subject, Issuer und Audience senden, um die aktuellen Login-Benutzer mehr Details zu identifizieren. Der Code kann wie folgt geändert werden:

import java.security.Key; 
import java.util.Base64; 
import java.util.Date; 
import java.util.UUID; 

import io.jsonwebtoken.Claims; 
import io.jsonwebtoken.Jwts; 
import io.jsonwebtoken.SignatureAlgorithm; 
import io.jsonwebtoken.impl.crypto.MacProvider; 

public class TokenUtil { 
    private static final Key secret = MacProvider.generateKey(SignatureAlgorithm.HS256); 
    private static final byte[] secretBytes = secret.getEncoded(); 
    private static final String base64SecretBytes = Base64.getEncoder().encodeToString(secretBytes); 

    private static String generateToken(String subject, String issuer, String audience) { 
     String id = UUID.randomUUID().toString().replace("-", ""); 
     Date now = new Date(); 
     Date exp = new Date(System.currentTimeMillis() + (1000 * 30)); // 30 seconds 

     String token = Jwts.builder() 
       .setId(id) 
       .setIssuedAt(now) 
       .setNotBefore(now) 
       .setExpiration(exp) 
       .setSubject(subject) 
       .setIssuer(issuer) 
       .setAudience(audience) 
       .signWith(SignatureAlgorithm.HS256, base64SecretBytes) 
       .compact(); 

     return token; 
    } 

    private static void verifyToken(String token) { 
     Claims claims = Jwts.parser() 
       .setSigningKey(base64SecretBytes) 
       .parseClaimsJws(token).getBody(); 

     System.out.println("----------------------------"); 
     System.out.println("ID: " + claims.getId()); 
     System.out.println("Subject: " + claims.getSubject()); 
     System.out.println("Issuer: " + claims.getIssuer()); 
     System.out.println("Expiration : " + claims.getExpiration()); 
     System.out.println("Not Before : "+claims.getNotBefore()); 
     System.out.println("Audience :: "+claims.getAudience()); 
    } 

    public static void main(String[] args) { 
     String token = generateToken("MySubject", "AH", "MyAudience"); 
     System.out.println("TOKEN :: "+token); 
     verifyToken(token); 
    } 
} 
Verwandte Themen