JJWT zielt darauf ab, die am einfachsten zu verwendende und verständliche Bibliothek zum Erstellen und Überprüfen von JSON Web Tokens (JWTs) und JSON Web Keys (JWKs) auf der JVM und Android zu sein.
JJWT ist eine reine Java-Implementierung, die ausschließlich auf den RFC-Spezifikationen der JOSE Working Group basiert:
RFC 7519: JSON-Web-Token (JWT)
RFC 7515: JSON-Websignatur (JWS)
RFC 7516: JSON-Webverschlüsselung (JWE)
RFC 7517: JSON Web Key (JWK)
RFC 7518: JSON-Webalgorithmen (JWA)
RFC 7638: Fingerabdruck des JSON-Webschlüssels
RFC 9278: JSON-Webschlüssel-Fingerabdruck-URI
RFC 7797: JWS-Option für nicht kodierte Nutzlast
RFC 8037: Edwards-Kurven-Algorithmen und JWKs
Es wurde von Les Hazlewood erstellt und wird von einer Community von Mitwirkenden unterstützt und gepflegt.
JJWT ist Open Source unter den Bedingungen der Apache 2.0-Lizenz.
PublicKey
toString()
SicherheitVoll funktionsfähig auf allen Java 7+ JDKs und Android
Automatische Sicherheits-Best Practices und -Behauptungen
Leicht zu erlernende und lesbare API
Praktische und lesbare, fließende Schnittstellen, ideal für die automatische IDE-Vervollständigung, um Code schnell zu schreiben
Vollständige RFC-Spezifikationskonformität bei allen implementierten Funktionen, getestet anhand RFC-spezifizierter Testvektoren
Stabile Implementierung mit fast 1.700 Tests und erzwungener 100-prozentiger Testcodeabdeckung. Jede einzelne Methode, Anweisung und bedingte Verzweigungsvariante in der gesamten Codebasis wird getestet und muss bei jedem Build weitergegeben werden.
Erstellen, Parsen und Überprüfen digital signierter kompakter JWTs (auch bekannt als JWSs) mit allen Standard-JWS-Algorithmen:
Kennung | Signaturalgorithmus |
---|---|
| HMAC mit SHA-256 |
| HMAC mit SHA-384 |
| HMAC mit SHA-512 |
| ECDSA mit P-256 und SHA-256 |
| ECDSA mit P-384 und SHA-384 |
| ECDSA mit P-521 und SHA-512 |
| RSASSA-PKCS-v1_5 mit SHA-256 |
| RSASSA-PKCS-v1_5 mit SHA-384 |
| RSASSA-PKCS-v1_5 mit SHA-512 |
| RSASSA-PSS mit SHA-256 und MGF1 mit SHA-256 1 |
| RSASSA-PSS mit SHA-384 und MGF1 mit SHA-384 1 |
| RSASSA-PSS mit SHA-512 und MGF1 mit SHA-512 1 |
| Edwards-Kurven-Algorithmus für digitale Signaturen 2 |
1. Erfordert Java 11 oder einen kompatiblen JCA-Provider (wie BouncyCastle) im Laufzeitklassenpfad.
2 . Erfordert Java 15 oder einen kompatiblen JCA-Provider (wie BouncyCastle) im Laufzeitklassenpfad.
Erstellen, Parsen und Entschlüsseln verschlüsselter kompakter JWTs (auch bekannt als JWEs) mit allen Standard-JWE-Verschlüsselungsalgorithmen:
Kennung | Verschlüsselungsalgorithmus |
---|---|
| AES_128_CBC_HMAC_SHA_256 authentifizierter Verschlüsselungsalgorithmus |
| AES_192_CBC_HMAC_SHA_384 authentifizierter Verschlüsselungsalgorithmus |
| AES_256_CBC_HMAC_SHA_512 authentifizierter Verschlüsselungsalgorithmus |
| AES GCM mit 128-Bit-Schlüssel 1 |
| AES GCM mit 192-Bit-Schlüssel 1 |
| AES GCM mit 256-Bit-Schlüssel 1 |
1 . Erfordert Java 8 oder einen kompatiblen JCA-Provider (wie BouncyCastle) im Laufzeitklassenpfad.
Alle Schlüsselverwaltungsalgorithmen zum Erhalten von JWE-Verschlüsselungs- und Entschlüsselungsschlüsseln:
Kennung | Schlüsselverwaltungsalgorithmus |
---|---|
| RSAES-PKCS1-v1_5 |
| RSAES OAEP unter Verwendung von Standardparametern |
| RSAES OAEP mit SHA-256 und MGF1 mit SHA-256 |
| AES Key Wrap mit Standardanfangswert unter Verwendung eines 128-Bit-Schlüssels |
| AES Key Wrap mit Standardanfangswert unter Verwendung eines 192-Bit-Schlüssels |
| AES Key Wrap mit Standardanfangswert unter Verwendung eines 256-Bit-Schlüssels |
| Direkte Verwendung eines gemeinsamen symmetrischen Schlüssels als CEK |
| Elliptische Kurve Diffie-Hellman Ephemeral Statische Schlüsselvereinbarung mit Concat KDF |
| ECDH-ES mit Concat KDF und CEK verpackt mit „A128KW“ |
| ECDH-ES mit Concat KDF und CEK verpackt mit „A192KW“ |
| ECDH-ES mit Concat KDF und CEK verpackt mit „A256KW“ |
| Schlüsselumbruch mit AES GCM unter Verwendung des 128-Bit-Schlüssels 1 |
| Schlüsselumbruch mit AES GCM unter Verwendung des 192-Bit-Schlüssels 1 |
| Schlüsselverpackung mit AES GCM unter Verwendung des 256-Bit-Schlüssels 1 |
| PBES2 mit HMAC SHA-256 und „A128KW“ Wrapping 1 |
| PBES2 mit HMAC SHA-384 und „A192KW“ Wrapping 1 |
| PBES2 mit HMAC SHA-512 und „A256KW“ Wrapping 1 |
1 . Erfordert Java 8 oder einen kompatiblen JCA-Provider (wie BouncyCastle) im Laufzeitklassenpfad.
Erstellen, Parsen und Überprüfen von JSON Web Keys (JWKs) in allen Standard-JWA-Schlüsselformaten unter Verwendung nativer Java- Key
:
JWK-Schlüsselformat | Java Key | JJWT Jwk -Typ |
---|---|---|
Symmetrischer Schlüssel | | |
Öffentlicher Schlüssel für elliptische Kurven | | |
Privater Elliptic-Curve-Schlüssel | | |
Öffentlicher RSA-Schlüssel | | |
Privater RSA-Schlüssel | | |
Privater XDH-Schlüssel | | |
Privater XDH-Schlüssel | | |
Öffentlicher EdDSA-Schlüssel | | |
Privater EdDSA-Schlüssel | | |
1 . Erfordert Java 15 oder einen kompatiblen JCA-Provider (wie BouncyCastle) im Laufzeitklassenpfad.
2 . Erfordert Java 15 oder einen kompatiblen JCA-Provider (wie BouncyCastle) im Laufzeitklassenpfad.
Komfortverbesserungen, die über die Spezifikation hinausgehen, wie z
Nutzlastkomprimierung für alle großen JWTs, nicht nur für JWEs
Anspruchsbehauptungen (bestimmte Werte erforderlich)
Fordern Sie POJO-Marshalling und Unmarshalling an, wenn Sie einen kompatiblen JSON-Parser (z. B. Jackson) verwenden.
Sichere Schlüsselgenerierung basierend auf gewünschten JWA-Algorithmen
und mehr…
Nichtkompakte Serialisierung und Analyse.
Diese Funktion wird möglicherweise in einer zukünftigen Version implementiert. Community-Beiträge sind willkommen!
Wenn Sie Probleme bei der Verwendung von JJWT haben, lesen Sie bitte zuerst die Dokumentation auf dieser Seite, bevor Sie Fragen stellen. Wir bemühen uns sehr, sicherzustellen, dass die Dokumentation von JJWT robust, kategorisiert mit einem Inhaltsverzeichnis und für jede Version auf dem neuesten Stand ist.
Wenn die Dokumentation oder das API JavaDoc nicht ausreicht und Sie entweder Fragen zur Benutzerfreundlichkeit haben oder sich über etwas nicht sicher sind, stellen Sie Ihre Frage bitte hier. Jedoch:
Bitte erstellen Sie kein GitHub-Problem, um eine Frage zu stellen.
Wir verwenden GitHub Issues, um umsetzbare Arbeiten zu verfolgen, die Änderungen am Design und/oder der Codebasis von JJWT erfordern. Wenn Sie eine Frage zur Benutzerfreundlichkeit haben, stellen Sie Ihre Frage stattdessen bitte hier. Wir können diese bei Bedarf in ein Problem umwandeln.
Wenn ein GitHub-Problem entsteht, das keine umsetzbare Arbeit für die Codebasis von JJWT darstellt, wird es umgehend geschlossen.
Wenn Sie keine Frage zur Benutzerfreundlichkeit haben und der Meinung sind, dass Sie einen legitimen Fehler oder eine Funktionsanfrage haben, besprechen Sie diese bitte ZUERST hier. Bitte führen Sie zunächst eine Schnellsuche durch, um zu sehen, ob es bereits eine Diskussion zu Ihrer Diskussion gibt, und nehmen Sie bei Bedarf an dieser Diskussion teil.
Wenn Sie das Gefühl haben, dass Sie bei der Behebung eines Fehlers helfen oder die neue Funktion selbst implementieren möchten, lesen Sie bitte als Nächstes den Abschnitt „Mitwirken“ durch, bevor Sie mit der Arbeit beginnen.
Einfache Pull Requests, die alles andere als den JJWT-Kerncode reparieren (Dokumentation, JavaDoc, Tippfehler, Testfälle usw.), werden immer geschätzt und werden mit hoher Wahrscheinlichkeit schnell zusammengeführt. Bitte senden Sie sie!
Wenn Sie jedoch die Funktionalität oder den Kerncode von JJWT ändern möchten oder das Bedürfnis verspüren, senden Sie bitte keine Pull-Anfrage, ohne eine neue JJWT-Diskussion zu starten und zunächst Ihre gewünschten Änderungen zu besprechen, bevor Sie mit der Arbeit daran beginnen .
Es wäre eine Schande, Ihre ernsthafte und wirklich geschätzte Pull-Anfrage abzulehnen, wenn sie möglicherweise nicht mit den Zielen des Projekts, den Designerwartungen oder der geplanten Funktionalität übereinstimmt. Leider mussten wir in der Vergangenheit große PRs ablehnen, weil sie nicht mit den Projekt- oder Designerwartungen übereinstimmten – alles nur, weil der PR-Autor sich nicht zuerst mit dem Team in Verbindung gesetzt hat, bevor er an einer Lösung gearbeitet hat.
Erstellen Sie also bitte zunächst eine neue JJWT-Diskussion zur Diskussion. Anschließend können wir die Diskussion leicht in ein Problem umwandeln und dann prüfen, ob (oder wie) eine PR gerechtfertigt ist. Danke schön!
Wenn Sie helfen möchten, aber nicht wissen, wo Sie anfangen sollen, besuchen Sie bitte die Seite „Hilfe gesucht“-Probleme und wählen Sie dort eines der Probleme aus. Wir besprechen und beantworten gerne Fragen in den Problemkommentaren.
Wenn Ihnen etwas davon nicht zusagt, ist das kein Grund zur Sorge! Jegliche Hilfe, die Sie anbieten möchten, wäre aufgrund der oben genannten Vorbehalte bezüglich der Bereitstellung von Pull-Anfragen dankbar. Wenn Sie sich nicht sicher sind, können Sie zunächst darüber diskutieren oder Fragen stellen. :) :)
JSON Web Token (JWT) ist ein allgemeines textbasiertes Nachrichtenformat zur kompakten und sicheren Übertragung von Informationen. Entgegen der landläufigen Meinung eignet sich JWT nicht nur zum Senden und Empfangen von Identitätstoken im Web – auch wenn dies der häufigste Anwendungsfall ist. JWTs können als Nachrichten für jede Art von Daten verwendet werden.
Ein JWT in seiner einfachsten Form besteht aus zwei Teilen:
Die primären Daten innerhalb des JWT, die als payload
bezeichnet werden, und
Ein JSON Object
mit Name/Wert-Paaren, die Metadaten über die payload
und die Nachricht selbst darstellen, genannt header
.
Eine JWT- payload
kann absolut alles sein – alles, was als Byte-Array dargestellt werden kann, wie zum Beispiel Strings, Bilder, Dokumente usw.
Da es sich bei einem JWT- header
jedoch um ein JSON- Object
handelt, wäre es sinnvoll, dass eine JWT- payload
auch ein JSON Object
sein könnte. In vielen Fällen bevorzugen Entwickler eine JSON- payload
, die Daten über einen Benutzer oder Computer oder ein ähnliches Identitätskonzept darstellt. Bei dieser Verwendung wird die payload
als JSON- Claims
Objekt bezeichnet, und jedes Name/Wert-Paar innerhalb dieses Objekts wird als claim
bezeichnet – jede Information darin „behauptet“ etwas über eine Identität.
Und obwohl es nützlich ist, etwas über eine Identität zu „behaupten“, kann das wirklich jeder. Wichtig ist, dass Sie den Ansprüchen vertrauen , indem Sie sicherstellen, dass sie von einer Person oder einem Computer stammen, dem Sie vertrauen.
Ein schönes Merkmal von JWTs ist, dass sie auf verschiedene Arten gesichert werden können. Ein JWT kann kryptografisch signiert (was wir als JWS bezeichnen) oder verschlüsselt (was es zu einem JWE macht) sein. Dies fügt dem JWT eine leistungsstarke Verifizierbarkeitsebene hinzu – ein JWS- oder JWE-Empfänger kann ein hohes Maß an Sicherheit haben, dass es von einer vertrauenswürdigen Person stammt, indem er eine Signatur überprüft oder entschlüsselt. Es ist diese Eigenschaft der Überprüfbarkeit, die JWT zu einer guten Wahl für das Senden und Empfangen sicherer Informationen, wie z. B. Identitätsansprüche, macht.
Schließlich ist JSON mit Leerzeichen für die menschliche Lesbarkeit nett, aber es ist kein sehr effizientes Nachrichtenformat. Daher können JWTs auf eine minimale Darstellung – im Wesentlichen Base64URL-codierte Zeichenfolgen – komprimiert (und sogar komprimiert) werden, sodass sie effizienter im Web übertragen werden können, beispielsweise in HTTP-Headern oder URLs.
Sobald Sie eine payload
und header
haben, wie werden diese für die Webübertragung komprimiert und wie sieht das endgültige JWT tatsächlich aus? Lassen Sie uns eine vereinfachte Version des Prozesses mit etwas Pseudocode durchgehen:
Angenommen, wir haben ein JWT mit einem JSON header
und einer einfachen Textnachrichten-Nutzlast:
Kopfzeile
{ „alg“: „keine“ }
Nutzlast
Das wahre Zeichen der Intelligenz ist nicht Wissen, sondern Vorstellungskraft.
Entfernen Sie alle unnötigen Leerzeichen im JSON:
String header = ' {"alg":"none"} '
String payload = ' The true sign of intelligence is not knowledge but imagination. '
Holen Sie sich jeweils die UTF-8-Bytes und die Base64URL-Kodierung:
String encodedHeader = base64URLEncode( header . getBytes( " UTF-8 " ) )
String encodedPayload = base64URLEncode( payload . getBytes( " UTF-8 " ) )
Verknüpfen Sie den codierten Header und die Ansprüche mit Punktzeichen ('.'):
String compact = encodedHeader + ' . ' + encodedPayload + ' . '
Der endgültige verkettete compact
JWT-String sieht folgendermaßen aus:
eyJhbGciOiJub25lIn0.VGhlIHRydWUgc2lnbiBvZiBpbnRlbGxpZ2VuY2UgaXMgbm90IGtub3dsZWRnZSBidXQgaW1hZ2luYXRpb24u.
Dies wird als „ungeschütztes“ JWT bezeichnet, da keine Sicherheit erforderlich war – keine digitalen Signaturen oder Verschlüsselung zum „Schutz“ des JWT, um sicherzustellen, dass es nicht von Dritten geändert werden kann.
Wenn wir das kompakte Formular digital signieren wollten, um zumindest sicherzustellen, dass niemand die Daten unbemerkt ändert, müssten wir noch ein paar weitere Schritte ausführen, die im Folgenden gezeigt werden.
Anstelle einer Nur-Text-Nutzlast wird im nächsten Beispiel der wahrscheinlich häufigste Nutzlasttyp verwendet – ein JSON- Object
das Informationen über eine bestimmte Identität enthält. Wir signieren das JWT außerdem digital, um sicherzustellen, dass es nicht ohne unser Wissen von Dritten geändert werden kann.
Angenommen, wir haben einen JSON- header
und eine payload
:
Kopfzeile
{
"alg" : " HS256 "
}
Nutzlast
{
"sub" : " Joe "
}
In diesem Fall gibt der header
an, dass der HS256
-Algorithmus (HMAC mit SHA-256) zum kryptografischen Signieren des JWT verwendet wird. Außerdem verfügt das payload
JSON-Objekt über einen einzelnen Anspruch, sub
mit dem Wert Joe
.
In der Spezifikation gibt es eine Reihe von Standardansprüchen, sogenannte Registered Claims, und sub
(für „Subject“) ist einer davon.
Entfernen Sie alle unnötigen Leerzeichen in beiden JSON-Objekten:
String header = ' {"alg":"HS256"} '
String claims = ' {"sub":"Joe"} '
Holen Sie sich jeweils ihre UTF-8-Bytes und die Base64URL-Kodierung:
String encodedHeader = base64URLEncode( header . getBytes( " UTF-8 " ) )
String encodedClaims = base64URLEncode( claims . getBytes( " UTF-8 " ) )
Verketten Sie den codierten Header und die Ansprüche mit einem Punktzeichen „.“ Trennzeichen:
String concatenated = encodedHeader + ' . ' + encodedClaims
Verwenden Sie ein ausreichend starkes kryptografisches Geheimnis oder einen privaten Schlüssel zusammen mit einem Signaturalgorithmus Ihrer Wahl (wir verwenden hier HMAC-SHA-256) und signieren Sie die verkettete Zeichenfolge:
SecretKey key = getMySecretKey()
byte [] signature = hmacSha256( concatenated, key )
Da es sich bei Signaturen immer um Byte-Arrays handelt, kodieren Sie die Signatur mit Base64URL und fügen Sie sie mit dem Punktzeichen „“ an die concatenated
Zeichenfolge an. Trennzeichen:
String compact = concatenated + ' . ' + base64URLEncode( signature )
Und da haben Sie es, der endgültige compact
String sieht so aus:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60AlD4
Dies wird als „JWS“ bezeichnet – kurz für signiertes JWT.
Natürlich möchte niemand dies manuell im Code tun, und schlimmer noch: Wenn Sie etwas falsch machen, könnten schwerwiegende Sicherheitsprobleme und Schwachstellen entstehen. Aus diesem Grund wurde JJWT geschaffen, um all dies für Sie zu erledigen: JJWT automatisiert sowohl die Erstellung von JWSs als auch das Parsing und die Überprüfung von JWSs vollständig für Sie.
Bisher haben wir ein ungeschütztes JWT und ein kryptografisch signiertes JWT (genannt „JWS“) gesehen. Beiden gemeinsam ist, dass alle darin enthaltenen Informationen für jedermann sichtbar sind – alle Daten sowohl im Header als auch in der Nutzlast sind öffentlich sichtbar. JWS stellt lediglich sicher, dass die Daten von niemandem geändert wurden – es hindert niemanden daran, sie einzusehen. Oftmals ist das völlig in Ordnung, da es sich bei den darin enthaltenen Daten nicht um vertrauliche Informationen handelt.
Aber was wäre, wenn Sie in einem JWT Informationen darstellen müssten, die als vertraulich gelten – etwa die Postanschrift, die Sozialversicherungsnummer oder die Bankkontonummer einer anderen Person?
In diesen Fällen benötigen wir ein vollständig verschlüsseltes JWT, kurz „JWE“ genannt. Ein JWE verwendet Kryptografie, um sicherzustellen, dass die Nutzlast vollständig verschlüsselt und authentifiziert bleibt, sodass Unbefugte die darin enthaltenen Daten nicht sehen oder unentdeckt ändern können. Insbesondere erfordert die JWE-Spezifikation, dass Algorithmen zur authentifizierten Verschlüsselung mit zugehörigen Daten verwendet werden, um Daten vollständig zu verschlüsseln und zu schützen.
Eine vollständige Übersicht über AEAD-Algorithmen würde den Rahmen dieser Dokumentation sprengen, aber hier ist ein Beispiel für ein endgültiges kompaktes JWE, das diese Algorithmen verwendet (Zeilenumbrüche dienen nur der besseren Lesbarkeit):
eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0. 6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ. AxY8DCtDaGlsbGljb3RoZQ. KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY. U0m_YmjN04DJvceFICbCVQ
Als nächstes besprechen wir, wie Sie JJWT in Ihrem Projekt installieren, und dann sehen wir, wie Sie die schöne fließende API von JJWT anstelle der riskanten String-Manipulation verwenden, um schnell und sicher JWTs, JWSs und JWEs zu erstellen.
Verwenden Sie Ihr bevorzugtes Maven-kompatibles Build-Tool, um die Abhängigkeiten von Maven Central abzurufen.
Die Abhängigkeiten können geringfügig abweichen, wenn Sie mit einem JDK-Projekt oder einem Android-Projekt arbeiten.
Wenn Sie ein JDK-Projekt (nicht Android) erstellen, sollten Sie die folgenden Abhängigkeiten definieren:
< dependency >
< groupId >io.jsonwebtoken</ groupId >
< artifactId >jjwt-api</ artifactId >
< version >0.12.6</ version >
</ dependency >
< dependency >
< groupId >io.jsonwebtoken</ groupId >
< artifactId >jjwt-impl</ artifactId >
< version >0.12.6</ version >
< scope >runtime</ scope >
</ dependency >
< dependency >
< groupId >io.jsonwebtoken</ groupId >
< artifactId >jjwt-jackson</ artifactId > <!-- or jjwt-gson if Gson is preferred -->
< version >0.12.6</ version >
< scope >runtime</ scope >
</ dependency >
<!-- Uncomment this next dependency if you are using:
- JDK 10 or earlier, and you want to use RSASSA-PSS (PS256, PS384, PS512) signature algorithms.
- JDK 10 or earlier, and you want to use EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.
- JDK 14 or earlier, and you want to use EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.
It is unnecessary for these algorithms on JDK 15 or later.
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId> or bcprov-jdk15to18 on JDK 7
<version>1.76</version>
<scope>runtime</scope>
</dependency>
-->
dependencies {
implementation ' io.jsonwebtoken:jjwt-api:0.12.6 '
runtimeOnly ' io.jsonwebtoken:jjwt-impl:0.12.6 '
runtimeOnly ' io.jsonwebtoken:jjwt-jackson:0.12.6 ' // or 'io.jsonwebtoken:jjwt-gson:0.12.6' for gson
/*
Uncomment this next dependency if you are using:
- JDK 10 or earlier, and you want to use RSASSA-PSS (PS256, PS384, PS512) signature algorithms.
- JDK 10 or earlier, and you want to use EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.
- JDK 14 or earlier, and you want to use EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.
It is unnecessary for these algorithms on JDK 15 or later.
*/
// runtimeOnly 'org.bouncycastle:bcprov-jdk18on:1.76' // or bcprov-jdk15to18 on JDK 7
}
Android-Projekte sollten die folgenden Abhängigkeiten und Proguard-Ausschlüsse sowie den optionalen BouncyCastle Provider
definieren:
Fügen Sie die Abhängigkeiten zu Ihrem Projekt hinzu:
dependencies {
api( ' io.jsonwebtoken:jjwt-api:0.12.6 ' )
runtimeOnly( ' io.jsonwebtoken:jjwt-impl:0.12.6 ' )
runtimeOnly( ' io.jsonwebtoken:jjwt-orgjson:0.12.6 ' ) {
exclude( group : ' org.json ' , module : ' json ' ) // provided by Android natively
}
/*
Uncomment this next dependency if you want to use:
- RSASSA-PSS (PS256, PS384, PS512) signature algorithms.
- EdECDH (X25519 or X448) Elliptic Curve Diffie-Hellman encryption.
- EdDSA (Ed25519 or Ed448) Elliptic Curve signature algorithms.
** AND ALSO ensure you enable the BouncyCastle provider as shown below **
*/
// implementation('org.bouncycastle:bcprov-jdk18on:1.76') // or bcprov-jdk15to18 for JDK 7
}
Sie können die folgenden Android Proguard-Ausschlussregeln verwenden:
-keepattributes InnerClasses -keep Klasse io.jsonwebtoken.** { *; } -keepnames Klasse io.jsonwebtoken.* { *; } -keepnames Schnittstelle io.jsonwebtoken.* { *; } -keep Klasse org.bouncycastle.** { *; } -keepnames Klasse org.bouncycastle.** { *; } -dontwarn org.bouncycastle.**
Wenn Sie Ed448
-RSASSA-PSS-Algorithmen (z. B. PS256
, PS384
und PS512
) Ed25519
EdECDH ( X25512
X448
Wenn die Anwendung eine aktualisierte Version von BouncyCastle ausführt, müssen Sie Folgendes tun:
Kommentieren Sie die BouncyCastle-Abhängigkeit wie oben im Abschnitt „Abhängigkeiten“ kommentiert aus.
Ersetzen Sie den alten benutzerdefinierten Android BC
Anbieter durch den aktualisierten.
Die Anbieterregistrierung muss früh im Lebenszyklus der Anwendung erfolgen, vorzugsweise in der Activity
Ihrer Anwendung als statischer Initialisierungsblock. Zum Beispiel:
class MainActivity : AppCompatActivity () {
companion object {
init {
Security .removeProvider( " BC " ) // remove old/legacy Android-provided BC provider
Security .addProvider( BouncyCastleProvider ()) // add 'real'/correct BC provider
}
}
// ... etc ...
}
Beachten Sie, dass die oben genannten JJWT-Abhängigkeitsdeklarationen alle nur eine Abhängigkeit zur Kompilierungszeit haben und der Rest als Laufzeitabhängigkeiten deklariert ist.
Dies liegt daran, dass JJWT so konzipiert ist, dass Sie nur auf die APIs angewiesen sind, die explizit für die Verwendung in Ihren Anwendungen entwickelt wurden, und alle anderen internen Implementierungsdetails – die sich ohne Vorwarnung ändern können – auf reine Laufzeitabhängigkeiten beschränkt sind. Dies ist ein äußerst wichtiger Punkt, wenn Sie eine stabile JJWT-Nutzung und Upgrades im Laufe der Zeit sicherstellen möchten:
JJWT garantiert die semantische Versionierungskompatibilität für alle seine Artefakte mit Ausnahme der |
Dies geschieht zu Ihrem Vorteil: Bei der Kuratierung der jjwt-api
-Datei wird große Sorgfalt darauf verwendet, sicherzustellen, dass sie alles enthält, was Sie benötigen, und so weit wie möglich abwärtskompatibel bleibt, sodass Sie sich beim Kompilieren sicher darauf verlassen können. Die Laufzeitstrategie jjwt-impl
.jar“ bietet den JJWT-Entwicklern die Flexibilität, die internen Pakete und Implementierungen jederzeit und nach Bedarf zu ändern. Dies hilft uns, Funktionen schneller und effizienter zu implementieren, Fehler zu beheben und Ihnen neue Versionen zu liefern.
Der größte Teil der Komplexität verbirgt sich hinter einer praktischen und lesbaren Builder-basierten fließenden Oberfläche, die sich hervorragend dazu eignet, sich beim schnellen Schreiben von Code auf die automatische Vervollständigung der IDE zu verlassen. Hier ist ein Beispiel:
import io . jsonwebtoken . Jwts ;
import io . jsonwebtoken . security . Keys ;
import java . security . Key ;
// We need a signing key, so we'll create one just for this example. Usually
// the key would be read from your application configuration instead.
SecretKey key = Jwts . SIG . HS256 . key (). build ();
String jws = Jwts . builder (). subject ( "Joe" ). signWith ( key ). compact ();
Wie einfach war das!?
In diesem Fall sind wir:
Erstellen eines JWT, bei dem der registrierte Anspruch sub
(Subject) auf Joe
gesetzt ist. Wir sind dann
Signieren des JWT mit einem Schlüssel, der für den HMAC-SHA-256-Algorithmus geeignet ist. Endlich sind wir es
Komprimieren in seine endgültige String
-Form. Ein signiertes JWT wird als „JWS“ bezeichnet.
Der resultierende jws
String sieht folgendermaßen aus:
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.1KP0SsvENi7Uz1oQc07aXTL7kpQG5jBNIybqr60AlD4
Lassen Sie uns nun das JWT überprüfen (Sie sollten immer JWTs verwerfen, die nicht mit einer erwarteten Signatur übereinstimmen):
assert Jwts . parser (). verifyWith ( key ). build (). parseSignedClaims ( jws ). getPayload (). getSubject (). equals ( "Joe" );
Hier passieren zwei Dinge. Der key
von zuvor wird verwendet, um die Signatur des JWT zu überprüfen. Wenn die Überprüfung des JWT fehlschlägt, wird eine SignatureException
(die JwtException
erweitert) ausgelöst. Unter der Annahme, dass das JWT verifiziert ist, analysieren wir die Ansprüche und stellen fest, dass das Subjekt auf Joe
gesetzt ist. Man muss Code-Einzeiler lieben, die es in sich haben!
NOTIZ | Typsichere JWTs: Um ein typsicheres |
Was aber, wenn das Parsen oder die Signaturvalidierung fehlschlägt? Sie können JwtException
abfangen und entsprechend reagieren:
try {
Jwts . parser (). verifyWith ( key ). build (). parseSignedClaims ( compactJws );
//OK, we can trust this JWT
} catch ( JwtException e ) {
//don't trust the JWT!
}
Nachdem wir nun eine kurze Einführung in die Erstellung und Analyse von JWTs erhalten haben, wollen wir uns ausführlicher mit der API von JJWT befassen.
Sie erstellen ein JWT wie folgt:
Verwenden Sie die Methode Jwts.builder()
um eine JwtBuilder
Instanz zu erstellen.
Legen Sie optional alle header
Parameter wie gewünscht fest.
Rufen Sie Builder-Methoden auf, um den Inhalt oder die Ansprüche der Nutzlast festzulegen.
Rufen Sie optional die Methoden signWith
oder encryptWith
auf, wenn Sie das JWT digital signieren oder verschlüsseln möchten.
Rufen Sie die Methode compact()
auf, um die resultierende kompakte JWT-Zeichenfolge zu erstellen.
Zum Beispiel:
String jwt = Jwts . builder () // (1)
. header () // (2) optional
. keyId ( "aKeyId" )
. and ()
. subject ( "Bob" ) // (3) JSON Claims, or
//.content(aByteArray, "text/plain") // any byte[] content, with media type
. signWith ( signingKey ) // (4) if signing, or
//.encryptWith(key, keyAlg, encryptionAlg) // if encrypting
. compact (); // (5)
Die JWT- payload
kann entweder byte[]
Inhalt (über content
) oder JSON-Ansprüche (wie subject
, claims
usw.) sein, aber nicht beides.
Es können entweder digitale Signaturen ( signWith
) oder Verschlüsselung ( encryptWith
) verwendet werden, jedoch nicht beides.
Ungeschützte JWTs : Wenn Sie die Builder-Methoden |
Ein JWT-Header ist ein JSON Object
, das Metadaten über den Inhalt, das Format und alle kryptografischen Vorgänge bereitstellt, die für die JWT- payload
relevant sind. JJWT bietet eine Reihe von Möglichkeiten, den gesamten Header und/oder mehrere einzelne Header-Parameter (Name/Wert-Paare) festzulegen.
Der einfachste und empfohlene Weg, einen oder mehrere JWT-Header-Parameter (Name/Wert-Paare) festzulegen, besteht darin, wie gewünscht den header()
-Builder von JwtBuilder
zu verwenden und dann seine and()
Methode aufzurufen, um zur weiteren Konfiguration zum JwtBuilder
zurückzukehren . Zum Beispiel:
String jwt = Jwts . builder ()
. header () // <----
. keyId ( "aKeyId" )
. x509Url ( aUri )
. add ( "someName" , anyValue )
. add ( mapValues )