JWT-Bibliothek (JSON Web Token) für Java [geschlossen]

76

Ich arbeite an einer Webanwendung, die mit Java und AngularJS entwickelt wurde, und habe mich für die Implementierung der Tokenauthentifizierung und -autorisierung entschieden. Zu Übungszwecken bin ich an dem Punkt angelangt, an dem ich die Anmeldeinformationen an den Server sende, ein zufälliges Token generiere, es speichere und an den Client zurücksende. Bei jeder Anfrage an den Server füge ich das Token in den Header ein und es funktioniert perfekt. Für die Authentifizierung ist der Standpunkt perfekt und würde nicht mehr brauchen.

Jetzt möchte ich jedoch den Benutzertyp (Administrator, regulärer Benutzer ...) sowie dessen ID oder ein anderes eindeutiges Feld verfolgen. Wie ich verstanden habe, muss ich das in dem Token verschlüsseln, das ich während der Anmeldeaktion an den Client zurücksende. Ist das korrekt?

Gibt es eine JWT-Bibliothek, die Sie verwendet haben und die solche Token generieren, verschlüsseln und entschlüsseln kann? Ein Link zur API- und Maven-Abhängigkeit der Bibliothek wäre sehr willkommen.

Vielen Dank

Marius Manastireanu
quelle
1
Wenn die Informationen, die Sie im Token speichern möchten, nicht vertraulich sind, müssen Sie das Token nicht unbedingt verschlüsseln. Ist eine Benutzer-ID und Berechtigungen etwas Geheimnisvolles? Wahrscheinlich nein. Sie müssen sicherstellen, dass nur Sie ein gültiges Token erstellen können. Der jwt-Ansatz besteht darin, das Token mit Hmac und einem geheimen Signaturschlüssel digital signieren zu lassen, um sicherzustellen, dass Sie seine Integrität und Herkunft überprüfen können. Meine Antwort unten enthält eine Bibliothek und ein Beispiel.
Marquez
1
Hallo .. Ich versuche auch diese JWT-Bibliothek zu implementieren und habe dies auf der Serverseite (Java) getan, aber wie kann ich auf meiner Front-End-Seite (Javascript) dekodieren? Welche Bibliothek haben Sie verwendet, um sie im Winkelbereich zu dekodieren?
Thiago Miranda de Oliveira
Thiago habe ich nicht. Der Ablauf war wie folgt: Benutzer meldet sich an -> Daten an Server gesendet -> Token erstellt -> an Client zurückgesendet. Immer wenn eine Anfrage an den Server gestellt wird, wurde das Token an den Header angehängt (ich habe dafür einen Interceptor implementiert). Die Validierung wurde auf dem Server durchgeführt und die richtige Antwort wurde zurückgesendet (ob autorisiert oder nicht).
Marius Manastireanu
2
Eine nützliche Seite im Umgang mit JWT: jwt.io
Vilmantas Baranauskas
@MariusManastireanu Das Token, das Sie von Angular senden, ist das gleiche Token, das Sie vom Server erhalten haben? Ich arbeite am gleichen Teil ... bitte helfen Sie
Kittu

Antworten:

53

JJWT soll die am einfachsten zu verwendende und zu verstehende JWT-Bibliothek für JVM und Android sein:

https://github.com/jwtk/jjwt

Les Hazlewood
quelle
4
Einfach, leicht und sauber und sofort funktioniert. Ich habe mich zuerst für das Google JsonToken entschieden und hier gewechselt, nachdem ich mit ungelösten Abhängigkeiten und Codeseiten herumgespielt hatte, um ein einfaches JWT zusammenzustellen.
Oliver Hausler
1
Wie kann ich Token-Diebstahl verhindern?
JHS
Wie kann ich Token Timeout wie in nodejs-jsonwebtoken
vanduc1102
Ich kann jjwt in einem einfachen Testprogramm verwenden. Wenn ich es jedoch in meiner Dropwizard-Anwendung verwende, wird beim Start der folgende Fehler angezeigt: java.lang.NoSuchFieldError: WRITE_DURATIONS_AS_TIMESTAMPS. Gedanken?
Ja.
1
"Wie kann ich mit Token Timeout umgehen?" - Gemäß der JWT-Spezifikation müssen Sie den Anspruch "exp" festlegen. Jjwt bietet hierfür eine praktische "setExpiration" -Methode.
Ja.
26

Wenn jemand eine Antwort braucht,

Ich habe diese Bibliothek verwendet: http://connect2id.com/products/nimbus-jose-jwt Maven hier: http://mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt/2.10.1

Marius Manastireanu
quelle
2
Bitte stellen Sie sicher, dass Sie die neueste Version verwenden. Die Bibliothek wird kontinuierlich überprüft und verbessert, und neue Algorithmen / Funktionen werden hinzugefügt: mvnrepository.com/artifact/com.nimbusds/nimbus-jose-jwt Ab Version 3.2 werden alle Standard-JWS-Signaturalgorithmen sowie die gesamte JWE-Verschlüsselung vollständig unterstützt Algen, außer für PBES2 und ECDH-ES.
Vladimir Dzhuvinov
Ich erhalte die folgende Fehlermeldung: java.lang.NoSuchMethodError: org.apache.commons.codec.binary.Base64.decodeBase64
Bear
Das obige Problem ist hier dokumentiert . Bitbucket.org/connect2id/nimbus-jose-jwt/issue/52/… . Ich habe das Problem behoben, indem ich die Methode byte [] decode () in com.nimbusds.jose.util.Base64Url geändert habe, um die Methode android.util.Base64.decode zu verwenden. Ist das der richtige Weg?
Bär
1
In Version 2.24 haben wir vom Apache Commons Codec zu einem internen Dienstprogramm gewechselt, um die BASE64-Codierung + -Decodierung zu handhaben. Damit wurde das Android-Problem mit dem Codec erfolgreich behoben. Weitere Informationen finden Sie in der Ausgabe bitbucket.org/connect2id/nimbus-jose-jwt/issue/63 . Außerdem sollten Sie jetzt eine noch bessere Leistung erzielen :)
Vladimir Dzhuvinov
@MariusManastireanu Hallo, ich beginne mit der AngularJS + Java-Authentifizierung mit JWT. Könnten Sie mich bitte anleiten oder einen Beispielcode zeigen, wie dies erreicht werden kann?
Kittu
19

Unter https://jwt.io/ finden Sie jwtImplementierungen in vielen Sprachen, einschließlich java. Die Site bietet auch einen Vergleich zwischen diesen Implementierungen (den von ihnen unterstützten Algorithmen und ...).

Für javadiese werden Bibliotheken erwähnt:

Alireza Fattahi
quelle
Danke, es hat mir geholfen, das JWT-Plugin für meine Play Framework App zu finden
Chabeee
1
Wie wählt ihr das aus? Was ist, wenn alle 4 Bibliotheken alle meine Anwendungsfälle abdecken?
Jkerak
6
@jkerak Gehen Sie mit dem, was Ihnen am einfachsten zu implementieren scheint. Wenn Ihnen alle Implementierungen griechisch erscheinen, wählen Sie die mit dem coolsten Namen. Das hat für mich gut geklappt.
TheFunk
13

Diese Bibliothek scheint gut zu funktionieren: https://code.google.com/p/jsontoken/ .

Es hängt von Google Guava ab. Hier sind die Maven-Artefakte:

<dependency>
    <groupId>com.googlecode.jsontoken</groupId>
    <artifactId>jsontoken</artifactId>
    <version>1.0</version>
</dependency>
<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>18.0</version>
</dependency>

Die Bibliothek wird tatsächlich von Google Wallet verwendet.

So erstellen Sie ein JWT, überprüfen es und deserialisieren es:

import java.security.InvalidKeyException;
import java.security.SignatureException;
import java.util.Calendar;
import java.util.List;

import net.oauth.jsontoken.JsonToken;
import net.oauth.jsontoken.JsonTokenParser;
import net.oauth.jsontoken.crypto.HmacSHA256Signer;
import net.oauth.jsontoken.crypto.HmacSHA256Verifier;
import net.oauth.jsontoken.crypto.SignatureAlgorithm;
import net.oauth.jsontoken.crypto.Verifier;
import net.oauth.jsontoken.discovery.VerifierProvider;
import net.oauth.jsontoken.discovery.VerifierProviders;

import org.apache.commons.lang3.StringUtils;
import org.bson.types.ObjectId;
import org.joda.time.DateTime;

import com.google.common.collect.Lists;
import com.google.gson.JsonObject;


/**
 * Provides static methods for creating and verifying access tokens and such. 
 * @author davidm
 *
 */
public class AuthHelper {

    private static final String AUDIENCE = "NotReallyImportant";

    private static final String ISSUER = "YourCompanyOrAppNameHere";

    private static final String SIGNING_KEY = "LongAndHardToGuessValueWithSpecialCharacters@^($%*$%";

    /**
     * Creates a json web token which is a digitally signed token that contains a payload (e.g. userId to identify 
     * the user). The signing key is secret. That ensures that the token is authentic and has not been modified.
     * Using a jwt eliminates the need to store authentication session information in a database.
     * @param userId
     * @param durationDays
     * @return
     */
    public static String createJsonWebToken(String userId, Long durationDays)    {
        //Current time and signing algorithm
        Calendar cal = Calendar.getInstance();
        HmacSHA256Signer signer;
        try {
            signer = new HmacSHA256Signer(ISSUER, null, SIGNING_KEY.getBytes());
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        }

        //Configure JSON token
        JsonToken token = new net.oauth.jsontoken.JsonToken(signer);
        token.setAudience(AUDIENCE);
        token.setIssuedAt(new org.joda.time.Instant(cal.getTimeInMillis()));
        token.setExpiration(new org.joda.time.Instant(cal.getTimeInMillis() + 1000L * 60L * 60L * 24L * durationDays));

        //Configure request object, which provides information of the item
        JsonObject request = new JsonObject();
        request.addProperty("userId", userId);

        JsonObject payload = token.getPayloadAsJsonObject();
        payload.add("info", request);

        try {
            return token.serializeAndSign();
        } catch (SignatureException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * Verifies a json web token's validity and extracts the user id and other information from it. 
     * @param token
     * @return
     * @throws SignatureException
     * @throws InvalidKeyException
     */
    public static TokenInfo verifyToken(String token)  
    {
        try {
            final Verifier hmacVerifier = new HmacSHA256Verifier(SIGNING_KEY.getBytes());

            VerifierProvider hmacLocator = new VerifierProvider() {

                @Override
                public List<Verifier> findVerifier(String id, String key){
                    return Lists.newArrayList(hmacVerifier);
                }
            };
            VerifierProviders locators = new VerifierProviders();
            locators.setVerifierProvider(SignatureAlgorithm.HS256, hmacLocator);
            net.oauth.jsontoken.Checker checker = new net.oauth.jsontoken.Checker(){

                @Override
                public void check(JsonObject payload) throws SignatureException {
                    // don't throw - allow anything
                }

            };
            //Ignore Audience does not mean that the Signature is ignored
            JsonTokenParser parser = new JsonTokenParser(locators,
                    checker);
            JsonToken jt;
            try {
                jt = parser.verifyAndDeserialize(token);
            } catch (SignatureException e) {
                throw new RuntimeException(e);
            }
            JsonObject payload = jt.getPayloadAsJsonObject();
            TokenInfo t = new TokenInfo();
            String issuer = payload.getAsJsonPrimitive("iss").getAsString();
            String userIdString =  payload.getAsJsonObject("info").getAsJsonPrimitive("userId").getAsString();
            if (issuer.equals(ISSUER) && !StringUtils.isBlank(userIdString))
            {
                t.setUserId(new ObjectId(userIdString));
                t.setIssued(new DateTime(payload.getAsJsonPrimitive("iat").getAsLong()));
                t.setExpires(new DateTime(payload.getAsJsonPrimitive("exp").getAsLong()));
                return t;
            }
            else
            {
                return null;
            }
        } catch (InvalidKeyException e1) {
            throw new RuntimeException(e1);
        }
    }


}

public class TokenInfo {
    private ObjectId userId;
    private DateTime issued;
    private DateTime expires;
    public ObjectId getUserId() {
        return userId;
    }
    public void setUserId(ObjectId userId) {
        this.userId = userId;
    }
    public DateTime getIssued() {
        return issued;
    }
    public void setIssued(DateTime issued) {
        this.issued = issued;
    }
    public DateTime getExpires() {
        return expires;
    }
    public void setExpires(DateTime expires) {
        this.expires = expires;
    }
}

Dies basiert auf Code hier: https://developers.google.com/wallet/instant-buy/about-jwts Und hier: https://code.google.com/p/wallet-online-sample-java/source /browse/src/com/google/wallet/online/jwt/util/WalletOnlineService.java?r=08b3333bd7260b20846d7d96d3cf15be8a128dfa

Marquez
quelle
5
Diese Bibliothek verwendet Tausende von Abhängigkeiten, die alle aufgelöst, kompiliert und Ihr Projekt durcheinander gebracht werden müssen. Warum nicht primär das verwenden, was in Java verfügbar ist?
Oliver Hausler
Nicht 1000s, es sind weniger als 20s Abhängigkeiten und arbeiten für mich.
Vanduc1102
Ist diese Bibliothek noch aktiv?
Arvindwill
Das Projekt kann nicht heruntergeladen werden. Immer ein 401
Val Martinez
8

IETF hat Jose Libs in seinem Wiki vorgeschlagen: http://trac.tools.ietf.org/wg/jose/trac/wiki

Ich würde empfehlen, sie zum Signieren zu verwenden. Ich bin kein Java-Typ, aber jose4j scheint eine gute Option zu sein. Hat auch schöne Beispiele: https://bitbucket.org/b_c/jose4j/wiki/JWS%20Examples

Update: jwt.io bietet einen übersichtlichen Vergleich mehrerer jwt-bezogener Bibliotheken und ihrer Funktionen. Ein Muss!

Ich würde gerne hören, was andere Java-Entwickler bevorzugen.

Priyeshj
quelle
jose4j bietet auch viel JWT-Unterstützung und gute Beispiele für die Verwendung zusätzlich zu den von Ihnen genannten JWS-Beispielen.
Brian Campbell
3

Wenn Sie nur nicht signierte unverschlüsselte Token analysieren müssen, können Sie diesen Code verwenden:

boolean parseJWT_2() {
    String authToken = getToken();
    String[] segments = authToken.split("\\.");
    String base64String = segments[1];
    int requiredLength = (int)(4 * Math.ceil(base64String.length() / 4.0));
    int nbrPaddings = requiredLength - base64String.length();

    if (nbrPaddings > 0) {
        base64String = base64String + "====".substring(0, nbrPaddings);
    }

    base64String = base64String.replace("-", "+");
    base64String = base64String.replace("_", "/");

    try {
        byte[] data = Base64.decode(base64String, Base64.DEFAULT);

        String text;
        text = new String(data, "UTF-8");
        tokenInfo = new Gson().fromJson(text, TokenInfo.class);
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }

    return true;
}
Anton Duzenko
quelle
2

https://github.com/networknt/jsontoken

Dies ist eine Abzweigung des ursprünglichen Google Jsontoken

Es wurde seit dem 11. September 2012 nicht aktualisiert und hängt von einigen alten Paketen ab.

Was habe ich getan:

Convert from Joda time to Java 8 time. So it requires Java 8.
Covert Json parser from Gson to Jackson as I don't want to include two Json parsers to my projects.
Remove google collections from dependency list as it is stopped long time ago.
Fix thread safe issue with Java Mac.doFinal call.

Alle vorhandenen Komponententests wurden zusammen mit einigen neu hinzugefügten Testfällen bestanden.

Hier ist ein Beispiel zum Generieren eines Tokens und zum Überprüfen des Tokens. Weitere Informationen finden Sie unter https://github.com/networknt/light Quellcode zur Verwendung.

Ich bin der Autor von jsontoken und Omni-Channel Application Framework.

Steve Hu
quelle