NGINX Plus Version 10 führte die Unterstützung für die Auslagerung der Authentifizierung von Web- und API-Diensten mithilfe von JSON Web Tokens (JWTs, ausgesprochen „Jotts“) ein. Seit der Veröffentlichung von R10 haben wir den Funktionsumfang mit jeder neuen Version kontinuierlich erweitert.
Ab NGINX Plus R14 unterstützt NGINX Plus JWTs, die verschachtelte Claims und Array-Daten enthalten. Beim Einsatz als API-Gateway kann NGINX Plus JWTs verwenden, um Clients zu authentifizieren, die Verbindungen zu Backend-Diensten und API-Endpunkten anfordern.
Gelegentlich wurde ich gebeten, eine Basiskonfiguration bereitzustellen, die NGINX Plus zur Authentifizierung von JWTs verwendet und anschließend auf Grundlage der JWT-Informationen komplexere Load-Balancing-Entscheidungen trifft. Die einfachste Lösung besteht darin, bei erfolgreicher Authentifizierung den Zugriff auf einen Dienst zuzulassen und die Verbindung bei fehlgeschlagener Authentifizierung zu blockieren oder umzuleiten.
Die Anleitung in diesem Beitrag ist ein umfassender Proof of Concept für die JWT-Authentifizierung und das inhaltsbasierte Routing mit NGINX Plus. Um ein möglichst breites Spektrum an Möglichkeiten abzudecken und die erforderlichen Vorkenntnisse oder Erfahrungen mit JWTs auf ein Minimum zu reduzieren, habe ich eine Einführung unter dem Titel „JWT 101“ erstellt. Damit können Sie diese Lösung – einschließlich Beispielen und Hintergrundinformationen – auch ohne jegliche JWT-Vorkenntnisse implementieren.
Wenn Sie bereits Erfahrung mit JWTs haben oder in Ihrer Umgebung bereits JWTs verwenden, können Sie die ersten beiden Abschnitte überspringen und die bereitgestellten NGINX Plus-Konfigurationsausschnitte an Ihre Umgebung anpassen, um anhand der Daten Ihrer JWT-Claims erweiterte Load-Balancing-Entscheidungen zu treffen.
Voraussetzungen
Dieses Dokument setzt eine Neuinstallation von NGINX Plus voraus, bei der sich die Standardkonfigurationsdateien an den folgenden Speicherorten befinden:
- /etc/nginx/nginx.conf
- /etc/nginx/conf.d/default.conf
Weitere Informationen zur Installation und zu den ersten Schritten mit NGINX Plus finden Sie im Administratorhandbuch für NGINX Plus.
Bei allen CLI-Befehlen werden root-Rechte vorausgesetzt. Benutzer ohne root-Rechte müssen daher in ihrer Umgebung über sudo-Berechtigungen verfügen.
Weitere Hintergrundinformationen und andere Anwendungsfälle für JWTs mit NGINX Plus finden Sie unter den folgenden Links:
- JWT-Modul – Referenzdokumentation
- Authentifizierung von API-Clients mit JWTs und NGINX Plus
- Authentifizierung von Benutzern für bestehende Anwendungen mit OpenID Connect und NGINX Plus
Erstellen eines JWT und des zugehörigen Signaturschlüssels
Die folgende Anleitung führt Sie Schritt für Schritt durch die Erstellung eines JWT von Grund auf mit den für unser Beispiel spezifischen Nutzdaten. Sie veranschaulicht, wie NGINX Plus für die grundlegende Verarbeitung von JWT-Claims konfiguriert wird. Wenn Sie anstelle des Beispiel-JWT ein vorhandenes JWT verwenden, müssen Sie sicherstellen, dass Ihre „secrets“-Datei die Base64URL-codierte Zeichenfolge enthält, die dem Signaturschlüssel entspricht, mit dem Sie das JWT erstellen. Wahrscheinlich müssen Sie außerdem die Claims in den JWT-Nutzdaten anpassen.
Hinweis: Unabhängig davon, wie Sie Ihr JWT generieren, müssen Sie die Base64URL-Codierung verwenden, die Padding (mithilfe des Zeichens =) sowie andere nicht HTTP-konforme Zeichen, die üblicherweise bei der Base64-Codierung verwendet werden, korrekt verarbeitet. Viele Tools erledigen dies automatisch, manuelle CLI-basierte Base64-Encoder und einige Tools zur JWT-Erstellung jedoch nicht. Weitere Informationen zur Base64URL-Codierung finden Sie unter Base64URL-Codierung von Brock Allen und in RFC 4648.
Für dieses Beispiel verwenden wir die Benutzeroberfläche auf jwt.io (die die Base64URL-Codierung korrekt durchführt), um ein symmetrisches HS256-JWT zu erstellen. Der folgende Screenshot zeigt, wie die Benutzeroberfläche aussieht, nachdem Sie die in den nachstehenden Anweisungen angegebenen Werte eingegeben haben und die Signatur verifiziert wurde.

Erstellen Sie in der Benutzeroberfläche unter jwt.io ein HS256-JWT, indem Sie die angegebenen Werte in den Feldern der Spalte „Decoded“ auf der rechten Seite überprüfen oder einfügen:
- Überprüfen Sie, ob der folgende Standardwert im Feld „HEADER“ angezeigt wird, und passen Sie den Inhalt bei Bedarf entsprechend an:
{ "alg": "HS256",
"typ": "JWT"
}- Ersetzen Sie im Feld „VERIFY SIGNATURE“ den Wert im Eingabefeld (standardmäßig
secret) durchnginx123. (Nehmen Sie diese Änderung vor, bevor Sie Daten in das Feld „PAYLOAD“ eingeben, um ein Problem zu vermeiden, das auftritt, wenn Sie die beiden Schritte in umgekehrter Reihenfolge ausführen.) - Ersetzen Sie den Inhalt des Felds „PAYLOAD“ durch Folgendes:
{ "exp": 1545091200,
"name": "Create New User",
"sub": "cuser",
"gname": "wheel",
"guid": "10",
"fullName": "John Doe",
"uname": "jdoe",
"uid": "222",
"sudo": true,
"dept": "IT",
"url": "http://secure.example.com"
}- Hinweis: Der
exp-Claim legt das Ablaufdatum und die Ablaufzeit des JWT fest und stellt diese als UNIX-Epochenzeit dar (die Anzahl der Sekunden seit Mitternacht UTC am 1. Januar 1970). Der Beispielwert entspricht Mitternacht UTC am 18. Dezember 2018. Um das Ablaufdatum anzupassen, ändern Sie die Epochenzeit. - Vergewissern Sie sich, dass die Leiste unter den Feldern blau ist und die Aufschrift „Signatur verifiziert“ trägt.
- Kopieren Sie den Wert aus der linken Spalte Encoded in eine Datei oder einen Puffer. Dies ist der vollständige Text des JWT, das der Benutzer jdoe vorlegen muss, um auf http://secure.example.com zuzugreifen. Wir verwenden es außerdem in unseren nachfolgenden Tests. Zur besseren Lesbarkeit stellen wir das JWT hier mit Zeilenumbrüchen dar. NGINX Plus muss es jedoch als einzeilige Zeichenfolge übergeben werden.eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOi
JDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkI
joiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIy
Iiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGx
lLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4
Führen Sie auf dem NGINX Plus-Host die folgenden Schritte aus, um die Schlüsseldatei zu erstellen, mit der NGINX Plus JWTs überprüft, die mit nginx123 signiert wurden:
- Führen Sie diesen Befehl aus, um die Base64URL-codierte Zeichenfolge zu erzeugen, die der Signaturzeichenfolge entspricht. (Die Befehle „
tr“ nehmen die für die Base64URL-Codierung erforderlichen Zeichenersetzungen vor.)
# echo -n nginx123 | base64 | tr '+/' '-_' | tr -d '='bmdpbngxMjM- Erstellen Sie im Verzeichnis /etc/nginx/ die Schlüsseldatei api_secret.jwk, die von NGINX Plus zur Überprüfung von JWT-Signaturen verwendet wird. Fügen Sie den folgenden Inhalt ein. Der Wert im Feld
kist die Base64URL-codierte Form vonnginx123, die wir im vorherigen Schritt generiert haben.
{"keys": [{
"k":"bmdpbngxMjM",
"kty":"oct"
}]
}NGINX Plus für die Verarbeitung von JWTs konfigurieren
Mit den Anweisungen in diesem Abschnitt wird NGINX Plus so konfiguriert, dass das in einer Anfrage enthaltene JWT validiert und eine geschützte Ressource bereitgestellt wird, wenn der Client autorisiert ist (anstelle der Standardseite, die nicht autorisierten Clients angezeigt wird). Außerdem definieren wir ein neues Protokollformat, das JWT-bezogene Informationen erfasst.
JWT-Validierung und inhaltsbasiertes Routing konfigurieren
In dieser Anleitung folgen wir der bewährten Standardpraxis und benennen die Konfigurationsdatei default.conf um, damit NGINX Plus sie nicht einliest. Außerdem erstellen wir eine neue Konfiguration speziell für Testzwecke. So können Sie die Standardkonfiguration problemlos wiederherstellen, wenn Sie die Tests abgeschlossen haben oder während der Tests ein Problem auftritt.
- Benennen Sie „default.conf“ um:
# mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.bak- Erstellen Sie eine neue Konfigurationsdatei namens jwt-test.conf in /etc/nginx/conf.d/. Fügen Sie den folgenden Inhalt ein. Damit werden die JWT-spezifische Protokollierung, die JWT-Validierung und das inhaltsbasierte Routing konfiguriert (eine vollständige Analyse folgt nach dem Codebeispiel).
server {
listen 80;
access_log /var/log/nginx/host.access.log jwt;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
# JWT validation
auth_jwt "JWT Test Realm" token=$arg_myjwt;
auth_jwt_key_file /etc/nginx/api_secret.jwk;
error_log /var/log/nginx/host.jwt.error.log debug;
if ( $jwt_claim_uid = 222 ) {
add_header X-jwt-claim-uid "$jwt_claim_uid" always;
add_header X-jwt-status "Redirect to $jwt_claim_url" always;
return 301 $jwt_claim_url;
}
if ( $jwt_claim_uid != 222 ) {
add_header X-jwt-claim-uid "$jwt_claim_uid" always;
add_header X-jwt-status "Invalid user, no redirect" always;
}
}
}Die Anweisungen im location-Block legen fest, wie NGINX Plus HTTP-Anfragen verarbeitet, die ein JWT enthalten. (Informationen zur Protokollierungskonfiguration, die durch die Direktive access_log definiert wird, finden Sie im nächsten Abschnitt.) NGINX Plus führt die folgenden Schritte aus:
- Extrahiert das JWT aus dem Argument „myjwt“ in der Abfragezeichenfolge (wie durch das Argument „
token“ der Direktive „auth_jwt“ angegeben). - Dekodiert das JWT mit dem Signaturschlüssel, der durch die Direktive
auth_jwt_key-fileangegeben wird (hier: api_secret.jwk). Die Nutzdaten werden dabei wie folgt verarbeitet (diese Aktionen sind Bestandteil der JWT-Verarbeitung und haben keine entsprechenden NGINX Plus-Direktiven):- Überprüft, ob das JWT noch nicht abgelaufen ist, d. h., ob das im Payload durch den Anspruch
expangegebene Ablaufdatum nicht in der Vergangenheit liegt. - Erstellt für jeden Anspruch in der Nutzlast ein Schlüssel-Wert-Paar. Der Schlüsselname ist eine Variable der Form
$jwt_claim_claim-name(zum Beispiel$jwt_claim_uidfür den Anspruchuid).
- Überprüft, ob das JWT noch nicht abgelaufen ist, d. h., ob das im Payload durch den Anspruch
- Protokolliert alle Fehler in /var/log/nginx/host.jwt.error.log auf der Protokollierungsstufe
debug. - Prüft, ob der Wert von
$jwt_claim_uidgleich222ist (wie durch die beidenif-Direktiven festgelegt), und sendet die entsprechende Antwort an den Client. Auf diese Weise werden Informationen im JWT für das inhaltsbasierte Routing verwendet.Hinweis: Die Verwendung derif-Direktive zur Auswertung von Variablen gilt im Allgemeinen nicht als Best Practice, und wir empfehlen üblicherweise, stattdessen diemap-Direktive zu verwenden. Für dieses einfache Beispiel funktioniert dieif-Direktive jedoch wie vorgesehen.- Wenn der Wert
222ist, sendet NGINX Plus eine Antwort, die den Client (mithilfe derreturn-Direktive) an die imurl-Claim des JWT angegebenen URL weiterleitet. Zu Debugging-Zwecken fügt NGINX Plus der Antwort zwei Header hinzu (mithilfe deradd_header-Direktiven): Der erste erfasst den Wert desuid-Claims, und der zweite hält fest, dass der Client weitergeleitet wurde. - Wenn der Wert nicht
222ist, stellt NGINX Plus die standardmäßige Indexseite bereit (wie durch die Direktivenrootundindexim selbenlocation-Block definiert). Auch hier fügt es zu Debugging-Zwecken Header hinzu, die den Wert des Claimsuiderfassen und festhalten, dass der Client keinen Zugriff auf die im JWT angegebene URL erhalten hat.
- Wenn der Wert
Die Konfiguration gewährt also nur autorisierten Benutzern Zugriff auf geschützte Ressourcen. Das heißt, Benutzer mit einem gültigen JWT erhalten Zugriff auf die im JWT angegebene URL, während Benutzer ohne gültiges JWT auf eine Standardseite zugreifen können.
JWT-Daten protokollieren
Wir schließen die Konfiguration der JWT-Verarbeitung für das inhaltsbasierte Routing ab, indem wir ein Protokollformat namens „jwt“ definieren, auf das die Direktive „access_log“ in jwt-test.conf verweist. Es erfasst JWT-Daten im Zugriffsprotokoll.
- Fügen Sie die folgende
log_format-Direktive zu /etc/nginx/nginx.conf hinzu:
log_format jwt '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" "$http_user_agent" '
'$jwt_header_alg $jwt_claim_uid $jwt_claim_url';- Dieses Format enthält die beiden JWT-Claims, die in dieser Anleitung verwendet werden (
uidundurl). Sie können jedoch die Daten eines beliebigen JWT-Claims protokollieren, indem Sie den Variablennamen verwenden, der dem Claim entspricht. Dieser hat die Form$jwt_claim_claim‑name. - Speichern Sie nginx.conf und führen Sie anschließend den folgenden Befehl aus, um die vollständige Konfiguration (einschließlich der neuen Datei jwt-test.conf) auf syntaktische Gültigkeit zu prüfen. Beheben Sie alle gemeldeten Fehler.
# nginx -t- Laden Sie NGINX Plus neu.
# nginx -s reloadTesten der Konfiguration
Mit einem Browser oder einem CLI-Tool wie curl können wir testen, ob NGINX Plus das JWT korrekt validiert, den Client authentifiziert, der es vorlegt, und inhaltsbasiertes Routing durchführt. (Um nur die Authentifizierung und Validierung, nicht aber das inhaltsbasierte Routing zu testen, kommentieren Sie die beiden if-Blöcke in jwt-test.conf aus.)
Um den Test auszuführen, fügen wir der Anfrage-URL das Argument „myjwt“ hinzu und geben dabei den vollständigen Text des JWT an, in dem der Claim „url“ den Wert „222“ hat. Auch hier haben wir zur besseren Darstellung Zeilenumbrüche eingefügt.
http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
jE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5le
GFtcGxlLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4
Hier ist der entsprechende curl-Befehl (ohne Zeilenumbrüche, sodass Sie ihn bei Bedarf kopieren und einfügen können):
# curl -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMjIyIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.YYQCNvzj17F726QvKoIiuRGeUBl_xAKj62Zvc9xkZb4Da der Wert des uid-Claims im JWT 222 ist, erwarten wir, dass NGINX Plus den Inhalt der zugriffsbeschränkten Seite http://secure.example.com anzeigt.
Nun testen wir, ob NGINX Plus den Inhalt der zugriffsbeschränkten Seite nicht anzeigt, wenn der url-Claim im JWT nicht 222 lautet, sondern stattdessen die Seite index.html des lokalen Servers bereitstellt, in diesem Fall http://example.com/index.html.
Zunächst generieren wir unter jwt.io ein weiteres JWT mit einem uid-Claim, dessen Wert nicht 222 ist. In diesem Beispiel verwenden wir den Wert 111. Hier ist die Anfrage-URL mit diesem JWT:
http://example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiO
jE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW
1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9
lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5l
eGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBgg
Der Befehl curl lautet:
# curl -v example.com/index.html?myjwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDUwOTEyMDAsIm5hbWUiOiJDcmVhdGUgTmV3IFVzZXIiLCJzdWIiOiJjdXNlciIsImduYW1lIjoid2hlZWwiLCJndWlkIjoiMTAiLCJmdWxsTmFtZSI6IkpvaG4gRG9lIiwidW5hbWUiOiJqZG9lIiwidWlkIjoiMTExIiwic3VkbyI6dHJ1ZSwiZGVwdCI6IklUIiwidXJsIjoiaHR0cDovL3NlY3VyZS5leGFtcGxlLmNvbSJ9.Ch9xqsGzB8fRVX-3CBuCxP1Ia3oGKB1OnO6qwi_oBggIn diesem Fall erwarten wir, dass NGINX Plus die Seite http://example.com/index.html bereitstellt.
Unter beiden Testbedingungen können Sie mit einem Tool zur Überprüfung von Headern (wie etwa curl oder den in einigen Browsern enthaltenen Entwicklertools) überprüfen, ob die neuen Header X-jwt-claim-uid und X-jwt-status zur Antwort hinzugefügt wurden.
Wenn während des Tests Probleme auftreten, überprüfen Sie die Zugriffs- und Fehlerprotokolle unter /var/log/nginx/host.jwt*. Insbesondere das Fehlerprotokoll gibt Aufschluss über Probleme bei der Verifizierung, beim Zugriff auf Ihre Verifizierungsdatei und Ähnliches.
Übergeben des JWT in einem Cookie
In unserem einfachen Beispiel extrahiert NGINX Plus das JWT aus dem Argument „myjwt“ in der Anfrage-URL. NGINX Plus unterstützt auch die Übergabe des JWT in einem Cookie (weitere Informationen finden Sie in der Referenzdokumentation zu „NGINX JWT“). Ändern Sie in jwt-test.conf die Direktive „auth_jwt“ so, dass das erste Element im Parameter „token“ $cookie anstelle von $arg ist:
auth_jwt "JWT Test Realm" token=$cookie_myjwt;Um das JWT in einem Cookie namens „myjwt“ zu übermitteln, lautet der entsprechende curl-Befehl:
# curl -v --cookie myjwt=JWT-text example.com/index.htmlProbieren Sie inhaltsbasiertes Routing mit JWTs selbst aus: Starten Sie noch heute Ihre kostenlose 30-Tage-Testversion von NGINX oder kontaktieren Sie uns, um Ihre Anwendungsfälle zu besprechen.
Über den Autor

Ähnliche Blogbeiträge
Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln
Beim NGINX Sprint 2022 besinnen wir uns auf unsere Open-Source-Wurzeln. Erfahren Sie mehr über die Initiativen, die wir im kommenden Jahr verfolgen, und teilen Sie uns mit, was Sie sich wünschen.

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen
Ein Ingress-Controller kann eines der leistungsstärksten Tools in Ihrem Kubernetes-Stack sein. Erfahren Sie, wie Sie Ihre Ingress-Anforderungen ermitteln, um die beste Option auszuwählen.
Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet
Wir haben kürzlich den Lösungsleitfaden zum NGINX Ingress Controller um Empfehlungen zur Dimensionierung für Amazon Elastic Kubernetes Service (EKS) ergänzt. In diesem Blogbeitrag erläutern wir, wie wir diese Empfehlungen erarbeitet haben, und stellen Ihnen alle Informationen zur Verfügung, die Sie benötigen, um selbst ähnliche Tests durchzuführen.

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77
Bei der Fehlersuche bei Datenverkehrsproblemen zwischen NGINX und Upstream-Servern konnte CDN77 die benötigten Daten nur aus dem Fehlerprotokoll mit aktivierter Debug-Ausgabe beziehen, was die Leistung beeinträchtigt und riesige Dateien erzeugt. Daher entwickelte das Team ein neues benutzerdefiniertes Modul, das ausschließlich die benötigten Daten protokolliert.
Ankündigung von NGINX Plus R16
NGINX Plus R16 ist eine einheitliche, elastische Ingress- und Egress-Schicht für Anwendungen, die die Funktionen eines Load Balancers, API-Gateways und einer WAF vereint und neue Features wie clusterfähige Ratenbegrenzung, Schlüssel-Wert-Speicher, „Random with Two Choices“, verbessertes UDP-Load-Balancing und vieles mehr bietet.
5 Gründe für den Umstieg auf softwarebasiertes Load Balancing
Entdecken Sie fünf Gründe für den Wechsel zu einem softwarebasierten Load Balancer wie NGINX Plus, darunter Kosteneinsparungen, die Einführung von DevOps und eine einheitliche Lösung für alle Umgebungen.