Sichere deine API-Ressourcen für die Kommunikation zwischen Maschinen
Lerne, wie du OAuth 2.0 und JWT nutzen kannst, um deine API-Ressourcen für die Kommunikation zwischen Maschinen zu sichern.
Beim Erstellen eines Projekts, das mehrere Dienste umfasst, ist die Sicherheit der API-Ressourcen eine kritische Angelegenheit. In diesem Artikel zeige ich dir, wie du OAuth 2.0 und JWT nutzen kannst, um die Kommunikation zwischen Diensten (Machine-to-Machine) zu sichern, und wie du rollenbasierte Zugriffskontrolle (RBAC) anwenden kannst, um das Prinzip des geringsten Privilegs einzuhalten.
Erste Schritte
Um mitzumachen, nehme ich an, dass du die folgenden Voraussetzungen hast:
- Ein Logto-Cloud-Konto oder eine selbst gehostete Logto-Instanz
- Mindestens zwei Dienste, die miteinander kommunizieren müssen
Zum Demonstrationszweck nehmen wir an, dass wir die folgenden Dienste haben:
- Ein Einkaufswagen-Dienst, der APIs bereitstellt, um Einkaufswagen zu verwalten
- Endpunkt:
https://cart.example.com/api
- Endpunkt:
- Ein Zahlungsdienst, der APIs bereitstellt, um Zahlungen zu verarbeiten
- Endpunkt:
https://payment.example.com/api
- Endpunkt:
Authentifizierungsablauf
Nun muss unser Einkaufswagen-Dienst den Zahlungsdienst aufrufen, um Zahlungen zu verarbeiten. Der Authentifizierungsablauf ist wie folgt:
Einige Schlüsselkonzepte im obigen Diagramm:
- JWT (RFC 7519): JSON Web Token. Siehe unseren vorherigen Artikel für eine Einführung in JWT.
- JWK (RFC 7517): JSON Web Key, der verwendet wird, um die Signatur eines JWT zu verifizieren. Ein JWK-Set ist eine Sammlung von JWKs.
- "client_credentials" Grant (RFC 6749): Ein Grant-Typ in OAuth 2.0. Er verwendet die Client-Anmeldeinformationen, um ein Zugriffstoken zu erhalten. Wir werden die Details in den folgenden Abschnitten demonstrieren.
Jeder Teilnehmer im obigen Diagramm hat eine Rolle im Authentifizierungsablauf:
- Einkaufswagen-Dienst: Der Client, der den Zahlungsdienst aufrufen muss. Obwohl es ein Dienst ist, ist es immer noch ein Client im Kontext von OAuth 2.0, und wir nennen solche Clients „Machine-to-Machine-Anwendungen“ in Logto.
- Logto: Der OAuth 2.0-Autorisierungsserver, der Zugriffstokens ausgibt.
- Zahlungsdienst: Die API-Ressource, die APIs bereitstellt, um Zahlungen zu verarbeiten.
Gehen wir den Authentifizierungsablauf Schritt für Schritt durch.
Erste Einrichtung
Um den Authentifizierungsablauf durchzuführen, müssen wir eine Machine-to-Machine-App (Einkaufswagen-Dienst) und eine API-Ressource (Zahlungsdienst) in Logto erstellen.
API-Ressource erstellen
Da unser Einkaufswagen-Dienst beim Durchführen der Authentifizierung über die API des Zahlungsdienstes Bescheid wissen muss, müssen wir zuerst eine API-Ressource erstellen. Gehe zur Logto-Konsole, klicke im linken Seitenbereich auf API-Ressourcen und klicke auf API-Ressource erstellen. Im geöffneten Dialog bieten wir einige Tutorials, um dir den Einstieg zu erleichtern. Du kannst auch auf Weiter ohne Tutorial klicken, um es zu überspringen.
Gib den API-Namen und die Kennung ein, zum Beispiel Zahlungsdienst
und https://payment.example.com/api
, und klicke dann auf API-Ressource erstellen.
Nach dem Erstellen der API-Ressource wirst du zur Detailseite weitergeleitet. Wir können sie vorerst so belassen.
Machine-to-Machine-App erstellen
Klicke im linken Seitenbereich auf Anwendungen und klicke auf Anwendung erstellen. Im geöffneten Dialog finde die Machine-to-Machine-Karte und klicke auf Starten.
Gib den Anwendungsnamen ein, zum Beispiel Einkaufswagen-Dienst
, und klicke auf Anwendung erstellen. Ein interaktiver Guide wird angezeigt, der dir beim Einrichten der Anwendung hilft. Du kannst dem Guide folgen, um die grundlegende Nutzung zu verstehen, oder auf Fertig und beenden klicken, um es zu überspringen.
Zugriffstoken anfordern
Da Machine-to-Machine-Anwendungen als sicher angenommen werden (z.B. sie sind in einem privaten Netzwerk bereitgestellt), können wir den OAuth 2.0 "client_credentials" Grant verwenden, um ein Zugriffstoken zu erhalten. Es verwendet Basic Authentication, um den Client zu authentifizieren:
- Die Anforderungs-URL ist der Token-Endpunkt deiner Logto-Instanz. Du kannst ihn unter dem Tab Erweiterte Einstellungen auf der Detailseite der Machine-to-Machine-App finden und kopieren.
- Die Anforderungsmethode ist
POST
. - Der Anforderungs-
Content-Type
-Header istapplication/x-www-form-urlencoded
. - Für den
Authorization
-Header ist der WertBasic <base64(app_id:app_secret)>
, wobeiapp_id
undapp_secret
die App-ID und das App-Geheimnis der Machine-to-Machine-App sind. Du kannst sie auf der Anwendungsdetailseite finden. - Der Anforderungstext muss den Grant-Typ und die API-Kennung angeben. Zum Beispiel
grant_type=client_credentials&resource=https://payment.example.com/api
.grant_type=client_credentials
: Der konstante Wert für den "client_credentials" Grant.resource=https://payment.example.com/api
: Die API-Kennung der API-Ressource, die der Client zugreifen möchte.- Wenn die Anwendung mit Berechtigungen (Scopes) autorisiert werden muss, kannst du auch die Scopes im Anforderungstext angeben. Zum Beispiel
scope=read:payment write:payment
. Wir behandeln Scopes später.
Hier ist ein Beispiel für die Anforderung mit curl
:
Eine erfolgreiche Antwort könnte so aussehen:
Anfrage mit Autorisierungsheader senden
Nun haben wir das Zugriffstoken und können es dem Authorization
-Header der Anfrage an die API-Ressource anhängen. Zum Beispiel, wenn wir die POST /payments
API des Zahlungsdienstes aufrufen wollen, können wir die folgende Anfrage senden:
JWT validieren
Du magst bemerken, dass der Zahlungsdienst das JWT mit dem JWK-Set validieren muss und möglicherweise einen lokalen JWK-Cache hat, um zu vermeiden, dass das JWK-Set jedes Mal von Logto abgerufen wird. Zum Glück gibt es aufgrund der Popularität von JWT viele Bibliotheken, die dir mit wenigen Codezeilen helfen können, das Ziel zu erreichen.
Diese Bibliotheken werden normalerweise "jose" (JavaScript Object Signing and Encryption) oder "jsonwebtoken" genannt. Zum Beispiel können wir in Node.js jose verwenden, um das JWT zu validieren:
Wenn die Validierung erfolgreich ist, wird die Variable payload
die decodierte JWT-Payload sein. Andernfalls wird ein Fehler ausgelöst.
Rollenbasierte Zugriffskontrolle anwenden
Nun haben wir die Kommunikation zwischen dem Einkaufswagen-Dienst und dem Zahlungsdienst erfolgreich gesichert. Der Authentifizierungsablauf stellt jedoch nur sicher, dass der Client der tatsächliche Einkaufswagen-Dienst ist, garantiert jedoch nicht, dass der Einkaufswagen-Dienst eine Erlaubnis hat, Aktionen auf dem Zahlungsdienst auszuführen.
Angenommen, wir wollen dem Einkaufswagen-Dienst erlauben, Zahlungen zu erstellen, aber nicht, Zahlungen zu lesen.
Berechtigungen definieren
In Logto sind "Scopes" und "Berechtigungen" austauschbar. Gehe zur Detailseite der API-Ressource des Zahlungsdienstes und navigiere zum Tab Berechtigungen. Es sollte jetzt leer sein. Klicke auf Berechtigung erstellen, gib read:payment
als den Berechtigungsnamen ein und Zahlungen lesen
als die Berechtigungserklärung. Dann klicke auf Berechtigung erstellen.
Wiederhole die obigen Schritte, um eine weitere Berechtigung mit dem Namen write:payment
und der Beschreibung Zahlungen erstellen
zu erstellen.
Rolle für Machine-to-Machine erstellen
Eine Rolle ist eine Gruppe von Berechtigungen. In Logto können Machine-to-Machine-Anwendungen Rollen zugewiesen werden, um Berechtigungen zu gewähren. Klicke im linken Seitenbereich auf "Rollen" und klicke auf Rolle erstellen.
- Gib
checkout
als Rollennamen ein undCheckout-Dienst
als Rollenbeschreibung. - Klicke auf Mehr Optionen anzeigen. Wähle "Machine-to-Machine-App-Rolle" als Rollentyp aus.
- Im Abschnitt "Zugewiesene Berechtigungen" klicke auf das Pfeilsymbol links vom API-Ressourcennamen (Zahlungsdienst) und wähle die
write:payment
-Berechtigung aus. - Klicke auf Rolle erstellen.
- Da wir bereits eine Machine-to-Machine-App (Einkaufswagen-Dienst) haben, können wir im nächsten Schritt direkt die Rolle zuweisen. Markiere das Kontrollkästchen links neben dem App-Namen (Einkaufswagen-Dienst) und klicke auf Anwendungen zuweisen.
Zugriffstoken mit Scopes anfordern
Neben den Anforderungstextparametern, die wir in Zugriffstoken anfordern erwähnt haben, können wir auch die Scopes im Anforderungstext angeben. Zum Beispiel, wenn wir die Berechtigung write:payment
anfordern wollen, können wir die folgende Anfrage senden:
Um mehrere Scopes anzufordern, kannst du sie mit Leerzeichen trennen. Zum Beispiel scope=write:payment read:payment
.
Scopes validieren
Wenn eine Aktion die Berechtigung write:payment
im Zahlungsdienst benötigt, können wir die Scopes validieren, indem wir feststellen, dass der scope
-Anspruch der JWT-Payload:
Fazit
Wenn du den Zugriff auf den Einkaufswagen-Dienst schützen möchtest, kannst du denselben Authentifizierungsablauf anwenden. Dieses Mal ist der Einkaufswagen-Dienst die API-Ressource, und der Client ist ein anderer Dienst, der Zugriff benötigt.
Mit Logto sind deine API-Ressourcen mit OAuth 2.0 und JWT gesichert, und du kannst das Prinzip des geringsten Privilegs durch die Anwendung von rollenbasierter Zugriffskontrolle einhalten. Außerdem kannst du Logto verwenden, um deine Benutzer und deren Berechtigungen zu verwalten und sogar mit Drittanbieter-Identitätsanbietern zu integrieren.