So führen Sie die JWT-Authentifizierung mit einem Angular 6 SPA durch
Veröffentlicht: 2022-03-11Heute sehen wir uns an, wie einfach es ist, die JSON-Web-Token-Authentifizierung (JWT) in Ihre Single-Page-Anwendung (SPA) von Angular 6 (oder höher) zu integrieren. Beginnen wir mit ein wenig Hintergrund.
Was sind JSON-Web-Token und warum werden sie verwendet?
Die einfachste und prägnanteste Antwort hier ist, dass sie bequem, kompakt und sicher sind. Schauen wir uns diese Behauptungen im Detail an:
- Praktisch : Die Verwendung eines JWT zur Authentifizierung beim Backend nach der Anmeldung erfordert das Setzen eines HTTP-Headers, eine Aufgabe, die durch eine Funktion oder Unterklassen leicht automatisiert werden kann, wie wir später sehen werden.
- Kompakt : Ein Token ist einfach eine base64-codierte Zeichenfolge, die einige Header-Felder und bei Bedarf eine Nutzlast enthält. Das gesamte JWT ist normalerweise kleiner als 200 Bytes, selbst wenn es signiert ist.
- Sicher : Obwohl dies nicht erforderlich ist, besteht eine großartige Sicherheitsfunktion von JWT darin, dass Token entweder mit der RSA-Verschlüsselung mit öffentlichen/privaten Schlüsselpaaren oder mit der HMAC-Verschlüsselung unter Verwendung eines gemeinsamen Geheimnisses signiert werden können. Dadurch wird die Herkunft und Gültigkeit eines Tokens sichergestellt.
Das alles läuft darauf hinaus, dass Sie eine sichere und effiziente Möglichkeit haben, Benutzer zu authentifizieren und dann Aufrufe an Ihre API-Endpunkte zu überprüfen, ohne Datenstrukturen analysieren oder Ihre eigene Verschlüsselung implementieren zu müssen.
Anwendungstheorie
Mit ein wenig Hintergrundwissen können wir nun untersuchen, wie dies in einer tatsächlichen Anwendung funktionieren würde. Für dieses Beispiel gehe ich davon aus, dass wir einen Node.js-Server haben, der unsere API hostet, und wir entwickeln eine SPA-Todo-Liste mit Angular 6. Lassen Sie uns auch mit dieser API-Struktur arbeiten:
-
/auth
→POST
(Benutzername und Passwort posten, um sich zu authentifizieren und ein JWT zurückzuerhalten) -
/todos
→GET
(gibt eine Liste mit Todo-Listenelementen für den Benutzer zurück) -
/todos/{id}
→GET
(gibt ein bestimmtes Todo-Listenelement zurück) -
/users
→GET
(gibt eine Liste von Benutzern zurück)
Wir werden in Kürze die Erstellung dieser einfachen Anwendung durchgehen, aber jetzt konzentrieren wir uns auf die Interaktion in der Theorie. Wir haben eine einfache Anmeldeseite, auf der der Benutzer seinen Benutzernamen und sein Passwort eingeben kann. Wenn das Formular gesendet wird, sendet es diese Informationen an den /auth
Endpunkt. Der Knotenserver kann den Benutzer dann auf geeignete Weise authentifizieren (Datenbanksuche, Abfrage eines anderen Webdiensts usw.), aber letztendlich muss der Endpunkt ein JWT zurückgeben.
Das JWT für dieses Beispiel enthält einige reservierte Ansprüche und einige private Ansprüche . Reservierte Ansprüche sind einfach von JWT empfohlene Schlüssel-Wert-Paare, die häufig zur Authentifizierung verwendet werden, während private Ansprüche Schlüssel-Wert-Paare sind, die nur für unsere App gelten:
Vorbehaltene Ansprüche
-
iss
: Aussteller dieses Tokens. Typischerweise der FQDN des Servers, kann aber beliebig sein, solange die Clientanwendung weiß, dass sie ihn erwartet. -
exp
: Ablaufdatum und -uhrzeit dieses Tokens. Dies ist in Sekunden seit Mitternacht des 1. Januar 1970 GMT (Unix-Zeit). -
nbf
: Nicht gültig vor Zeitstempel. Wird nicht oft verwendet, gibt aber eine Untergrenze für das Gültigkeitsfenster an. Gleiches Format wieexp
.
Private Forderungen
-
uid
: Benutzer-ID des angemeldeten Benutzers. -
role
: Dem angemeldeten Benutzer zugewiesene Rolle.
Unsere Informationen werden base64-codiert und mit HMAC mit dem gemeinsamen Schlüssel todo-app-super-shared-secret
signiert. Unten sehen Sie ein Beispiel dafür, wie das JWT aussieht:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ0b2RvYXBpIiwibmJmIjoxNDk4MTE3NjQyLCJleHAiOjE0OTgxMjEyNDIsInVpZCI6MSwicm9sZSI6ImFkbWluIn0.ZDz_1vcIlnZz64nSM28yA1s-4c_iw3Z2ZtP-SgcYRPQ
Diese Zeichenfolge ist alles, was wir brauchen, um sicherzustellen, dass wir ein gültiges Login haben, um zu wissen, welcher Benutzer verbunden ist, und um sogar zu wissen, welche Rolle(n) der Benutzer hat.
Die meisten Bibliotheken und Anwendungen speichern dieses JWT zum einfachen Abrufen in localStorage
oder sessionStorage
, aber dies ist nur gängige Praxis. Was Sie mit dem Token tun, liegt bei Ihnen, solange Sie es für zukünftige API-Aufrufe bereitstellen können.
Wenn die SPA nun einen Aufruf an einen der geschützten API-Endpunkte tätigen möchte, muss sie einfach das Token im Authorization
-HTTP-Header mitsenden.
Authorization: Bearer {JWT Token}
Hinweis : Auch dies ist einfach gängige Praxis. JWT schreibt keine bestimmte Methode vor, um sich selbst an den Server zu senden. Sie können es auch an die URL anhängen oder in einem Cookie senden.
Sobald der Server das JWT empfängt, kann er es decodieren, die Konsistenz mithilfe des HMAC Shared Secret sicherstellen und den Ablauf mithilfe der Felder exp
und nbf
überprüfen. Es könnte auch das iss
-Feld verwenden, um sicherzustellen, dass es die ursprüngliche ausstellende Partei dieses JWT war.
Sobald der Server mit der Gültigkeit des Tokens zufrieden ist, können die im JWT gespeicherten Informationen verwendet werden. Beispielsweise gibt uns die von uns eingeschlossene uid
die ID des Benutzers, der die Anfrage stellt. Für dieses spezielle Beispiel haben wir auch das role
eingefügt, mit dem wir entscheiden können, ob der Benutzer auf einen bestimmten Endpunkt zugreifen darf oder nicht. (Ob Sie diesen Informationen vertrauen oder lieber eine Datenbanksuche durchführen möchten, hängt von der erforderlichen Sicherheitsstufe ab.)
function getTodos(jwtString) { var token = JWTDecode(jwtstring); if( Date.now() < token.nbf*1000) { throw new Error('Token not yet valid'); } if( Date.now() > token.exp*1000) { throw new Error('Token has expired'); } if( token.iss != 'todoapi') { throw new Error('Token not issued here'); } var userID = token.uid; var todos = loadUserTodosFromDB(userID); return JSON.stringify(todos); }
Lassen Sie uns eine einfache Todo-App erstellen
Um mitzumachen, müssen Sie eine aktuelle Version von Node.js (6.x oder höher), npm (3.x oder höher) und Angular-Cli installiert haben. Wenn Sie Node.js installieren müssen, das npm enthält, befolgen Sie bitte die Anweisungen hier. Danach kann angular-cli
mit npm
(oder yarn
, wenn Sie es installiert haben) installiert werden:
# installation using npm npm install -g @angular/cli # installation using yarn yarn global add @angular/cli
Ich werde nicht näher auf die Angular 6-Boilerplate eingehen, die wir hier verwenden werden, aber für den nächsten Schritt habe ich ein Github-Repository erstellt, um eine kleine Aufgabenanwendung zu speichern, um zu veranschaulichen, wie einfach es ist, Ihrer App JWT-Authentifizierung hinzuzufügen. Klonen Sie es einfach mit dem Folgenden:
git clone https://github.com/sschocke/angular-jwt-todo.git cd angular-jwt-todo git checkout pre-jwt
Der Befehl git checkout pre-jwt
wechselt zu einem benannten Release, in dem JWT nicht implementiert wurde.
Es sollten zwei Ordner namens server
und client
sein. Der Server ist ein Node-API-Server, der unsere Basis-API hostet. Der Client ist unsere Angular 6 App.
Der Node-API-Server
Installieren Sie zunächst die Abhängigkeiten und starten Sie den API-Server.
cd server # installation using npm npm install # or installation using yarn yarn node app.js
Sie sollten in der Lage sein, diesen Links zu folgen und eine JSON-Darstellung der Daten zu erhalten. Bis zur Authentifizierung haben wir den /todos
-Endpunkt fest codiert, um die Aufgaben für userID=1
:
- http://localhost:4000: Testseite, um zu sehen, ob der Node-Server läuft
- http://localhost:4000/api/users: Liste der Benutzer auf dem System zurückgeben
- http://localhost:4000/api/todos: Liste der Aufgaben für
userID=1
Die Angular-App
Um mit der Client-App zu beginnen, müssen wir auch die Abhängigkeiten installieren und den Dev-Server starten.
cd client # using npm npm install npm start # using yarn yarn yarn start
Hinweis : Abhängig von Ihrer Leitungsgeschwindigkeit kann es eine Weile dauern, bis alle Abhängigkeiten heruntergeladen sind.
Wenn alles gut läuft, sollten Sie jetzt so etwas sehen, wenn Sie zu http://localhost:4200 navigieren:
Authentifizierung über JWT hinzufügen
Um Unterstützung für die JWT-Authentifizierung hinzuzufügen, verwenden wir einige verfügbare Standardbibliotheken, die es einfacher machen. Natürlich können Sie auf diese Annehmlichkeiten verzichten und alles selbst umsetzen, aber das würde hier den Rahmen sprengen.
Lassen Sie uns zunächst eine Bibliothek auf der Clientseite installieren. Es wird von Auth0 entwickelt und gepflegt, einer Bibliothek, mit der Sie einer Website eine Cloud-basierte Authentifizierung hinzufügen können. Die Nutzung der Bibliothek selbst erfordert nicht, dass Sie ihre Dienste nutzen.
cd client # installation using npm npm install @auth0/angular-jwt # installation using yarn yarn add @auth0/angular-jwt
Wir kommen gleich zum Code, aber wenn wir schon dabei sind, lassen Sie uns auch die Serverseite einrichten. Wir verwenden die Bibliotheken body-parser
parser , jsonwebtoken
und express-jwt
, damit Node JSON POST-Bodys und JWTs versteht.
cd server # installation using npm npm install body-parser jsonwebtoken express-jwt # installation using yarn yarn add body-parser jsonwebtoken express-jwt
API-Endpunkt für die Authentifizierung
Zuerst brauchen wir eine Möglichkeit, Benutzer zu authentifizieren, bevor wir ihnen ein Token geben. Für unsere einfache Demo richten wir einfach einen festen Authentifizierungsendpunkt mit einem fest codierten Benutzernamen und Passwort ein. Dies kann so einfach oder so komplex sein, wie es Ihre Anwendung erfordert. Das Wichtigste ist, ein JWT zurückzusenden.
Fügen Sie in server/app.js
einen Eintrag unter den anderen require
Zeilen wie folgt hinzu:
const bodyParser = require('body-parser'); const jwt = require('jsonwebtoken'); const expressJwt = require('express-jwt');
Sowie folgendes:
app.use(bodyParser.json()); app.post('/api/auth', function(req, res) { const body = req.body; const user = USERS.find(user => user.username == body.username); if(!user || body.password != 'todo') return res.sendStatus(401); var token = jwt.sign({userID: user.id}, 'todo-app-super-shared-secret', {expiresIn: '2h'}); res.send({token}); });
Dies ist hauptsächlich einfacher JavaScript-Code. Wir erhalten den JSON-Text, der an den /auth
Endpunkt übergeben wurde, finden einen Benutzer, der mit diesem Benutzernamen übereinstimmt, überprüfen, ob wir einen Benutzer und das Passwort haben und geben einen 401 Unauthorized
HTTP-Fehler zurück, wenn dies nicht der Fall ist.
Der wichtige Teil ist die Token-Generierung, und wir werden das nach seinen drei Parametern aufschlüsseln. Die Syntax für sign
lautet wie folgt: jwt.sign(payload, secretOrPrivateKey, [options, callback])
, wobei:
-
payload
ist ein Objektliteral von Schlüssel-Wert-Paaren, die Sie in Ihrem Token codieren möchten. Diese Informationen können dann von jedem, der über den Entschlüsselungsschlüssel verfügt, aus dem Token entschlüsselt werden. In unserem Beispiel codieren wir dieuser.id
, damit wir wissen, mit welchem Benutzer wir es zu tun haben, wenn wir den Token erneut im Backend zur Authentifizierung erhalten. -
secretOrPrivateKey
ist entweder ein gemeinsam genutzter geheimer Schlüssel für die HMAC-Verschlüsselung – das haben wir der Einfachheit halber in unserer App verwendet – oder ein privater Schlüssel für die RSA/ECDSA-Verschlüsselung. -
options
stellt eine Vielzahl von Optionen dar, die in Form von Schlüssel-Wert-Paaren an den Encoder übergeben werden können. Typischerweise geben wir mindestensexpiresIn
(wirdexp
reservierter Anspruch) undissuer
(iss
reservierter Anspruch) an, damit ein Token nicht ewig gültig ist und der Server überprüfen kann, ob er das Token tatsächlich ursprünglich ausgegeben hat. -
callback
ist eine Funktion, die aufgerufen wird, nachdem die Codierung abgeschlossen ist, falls man die Codierung des Tokens asynchron handhaben möchte.
(Sie können auch mehr Details zu options
und zur Verwendung von Public-Key-Kryptographie anstelle eines gemeinsamen geheimen Schlüssels lesen.)
Angular 6 JWT-Integration
Damit Angular 6 mit unserem JWT funktioniert, ist es ganz einfach, angular-jwt
. Fügen Sie einfach Folgendes zu client/src/app/app.modules.ts
:
import { JwtModule } from '@auth0/angular-jwt'; // ... export function tokenGetter() { return localStorage.getItem('access_token'); } @NgModule({ // ... imports: [ BrowserModule, AppRoutingModule, HttpClientModule, FormsModule, // Add this import here JwtModule.forRoot({ config: { tokenGetter: tokenGetter, whitelistedDomains: ['localhost:4000'], blacklistedRoutes: ['localhost:4000/api/auth'] } }) ], // ... }
Das ist im Grunde alles, was erforderlich ist. Natürlich müssen wir noch etwas Code hinzufügen, um die anfängliche Authentifizierung durchzuführen, aber die angular-jwt
Bibliothek kümmert sich darum, das Token zusammen mit jeder HTTP-Anforderung zu senden.

- Die Funktion
tokenGetter()
macht genau das, was sie sagt, aber wie sie implementiert wird, liegt ganz bei Ihnen. Wir haben uns entschieden, das Token zurückzugeben, das wir inlocalStorage
. Es steht Ihnen natürlich frei, jede andere gewünschte Methode bereitzustellen, solange sie die JSON-Web-Token- codierte Zeichenfolge zurückgibt. - Die Option
whiteListedDomains
ist vorhanden, damit Sie einschränken können, an welche Domänen das JWT gesendet wird, sodass öffentliche APIs Ihr JWT nicht ebenfalls erhalten. - Mit der Option
blackListedRoutes
können Sie bestimmte Routen angeben, die das JWT nicht erhalten sollen, selbst wenn sie sich in einer Whitelist-Domäne befinden. Beispielsweise muss der Authentifizierungsendpunkt es nicht empfangen, weil es keinen Sinn macht: Das Token ist normalerweise null, wenn es sowieso aufgerufen wird.
Damit alles zusammen funktioniert
An diesem Punkt haben wir eine Möglichkeit, ein JWT für einen bestimmten Benutzer mithilfe des /auth
Endpunkts in unserer API zu generieren, und wir haben die Installation auf Angular durchgeführt, um mit jeder HTTP-Anforderung ein JWT zu senden. Toll, aber Sie könnten darauf hinweisen, dass sich für den Benutzer absolut nichts geändert hat. Und du hättest recht. Wir können immer noch zu jeder Seite in unserer App navigieren und jeden API-Endpunkt aufrufen, ohne auch nur ein JWT zu senden. Nicht gut!
Wir müssen unsere Client-App aktualisieren, um uns Gedanken darüber zu machen, wer angemeldet ist, und auch unsere API so aktualisieren, dass ein JWT erforderlich ist. Lass uns anfangen.
Für die Anmeldung benötigen wir eine neue Angular-Komponente. Der Kürze halber werde ich dies so einfach wie möglich halten. Wir benötigen außerdem einen Dienst, der alle unsere Authentifizierungsanforderungen erfüllt, und einen Angular Guard, um die Routen zu schützen, auf die vor der Anmeldung nicht zugegriffen werden sollte. Wir werden im Kontext der Clientanwendung Folgendes tun.
cd client ng g component login --spec=false --inline-style ng g service auth --flat --spec=false ng g guard auth --flat --spec=false
Dies sollte vier neue Dateien im client
Ordner generiert haben:
src/app/login/login.component.html src/app/login/login.component.ts src/app/auth.service.ts src/app/auth.guard.ts
Als Nächstes müssen wir den Authentifizierungsdienst und den Schutz für unsere App bereitstellen. client/src/app/app.modules.ts
:
import { AuthService } from './auth.service'; import { AuthGuard } from './auth.guard'; // ... providers: [ TodoService, UserService, AuthService, AuthGuard ],
Aktualisieren Sie dann das Routing in client/src/app/app-routing.modules.ts
, um den Authentifizierungswächter zu verwenden und eine Route für die Anmeldekomponente bereitzustellen.
// ... import { LoginComponent } from './login/login.component'; import { AuthGuard } from './auth.guard'; const routes: Routes = [ { path: 'todos', component: TodoListComponent, canActivate: [AuthGuard] }, { path: 'users', component: UserListComponent, canActivate: [AuthGuard] }, { path: 'login', component: LoginComponent}, // ...
Aktualisieren Sie schließlich client/src/app/auth.guard.ts
mit den folgenden Inhalten:
import { Injectable } from '@angular/core'; import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; @Injectable() export class AuthGuard implements CanActivate { constructor(private router: Router) { } canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) { if (localStorage.getItem('access_token')) { return true; } this.router.navigate(['login']); return false; } }
Für unsere Demoanwendung prüfen wir einfach, ob ein JWT im lokalen Speicher vorhanden ist. In realen Anwendungen würden Sie das Token entschlüsseln und seine Gültigkeit, seinen Ablauf usw. überprüfen. Dazu könnten Sie beispielsweise JwtHelperService verwenden.
An dieser Stelle leitet Sie unsere Angular-App jetzt immer auf die Anmeldeseite weiter, da wir keine Möglichkeit haben, uns anzumelden. Lassen Sie uns das korrigieren, beginnend mit dem Authentifizierungsdienst in client/src/app/auth.service.ts
:
import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @Injectable() export class AuthService { constructor(private http: HttpClient) { } login(username: string, password: string): Observable<boolean> { return this.http.post<{token: string}>('/api/auth', {username: username, password: password}) .pipe( map(result => { localStorage.setItem('access_token', result.token); return true; }) ); } logout() { localStorage.removeItem('access_token'); } public get loggedIn(): boolean { return (localStorage.getItem('access_token') !== null); } }
Unser Authentifizierungsdienst hat nur zwei Funktionen, login
und logout
:
-
login
POST
sendet den bereitgestelltenusername
und daspassword
an unser Backend und setzt dasaccess_token
inlocalStorage
, wenn es eines zurückerhält. Auf eine Fehlerbehandlung wird hier der Einfachheit halber verzichtet. -
logout
löscht einfachaccess_token
auslocalStorage
, sodass ein neues Token erworben werden muss, bevor wieder auf etwas weiteres zugegriffen werden kann. -
loggedIn
ist eine boolesche Eigenschaft, mit der wir schnell feststellen können, ob der Benutzer eingeloggt ist oder nicht.
Und schließlich die Login-Komponente. Diese haben keinen Bezug zur tatsächlichen Arbeit mit JWT, also kopieren Sie sie und fügen Sie sie in client/src/app/login/login.components.html
:
<h4 *ngIf="error">{{error}}</h4> <form (ngSubmit)="submit()"> <div class="form-group col-3"> <label for="username">Username</label> <input type="text" name="username" class="form-control" [(ngModel)]="username" /> </div> <div class="form-group col-3"> <label for="password">Password</label> <input type="password" name="password" class="form-control" [(ngModel)]="password" /> </div> <div class="form-group col-3"> <button class="btn btn-primary" type="submit">Login</button> </div> </form>
Und client/src/app/login/login.components.ts
benötigt:
import { Component, OnInit } from '@angular/core'; import { AuthService } from '../auth.service'; import { Router } from '@angular/router'; import { first } from 'rxjs/operators'; @Component({ selector: 'app-login', templateUrl: './login.component.html' }) export class LoginComponent { public username: string; public password: string; public error: string; constructor(private auth: AuthService, private router: Router) { } public submit() { this.auth.login(this.username, this.password) .pipe(first()) .subscribe( result => this.router.navigate(['todos']), err => this.error = 'Could not authenticate' ); } }
Voila, unser Anmeldebeispiel für Angular 6:
An diesem Punkt sollten wir uns anmelden können (mit jemma
, paul
oder sebastian
mit dem Passwort todo
) und alle Bildschirme wieder sehen können. Aber unsere Anwendung zeigt die gleichen Navigationskopfzeilen und keine Möglichkeit, sich abzumelden, unabhängig vom aktuellen Status. Lassen Sie uns das beheben, bevor wir mit der Reparatur unserer API fortfahren.
Ersetzen Sie in client/src/app/app.component.ts
die gesamte Datei durch Folgendes:
import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { AuthService } from './auth.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { constructor(private auth: AuthService, private router: Router) { } logout() { this.auth.logout(); this.router.navigate(['login']); } }
Und für client/src/app/app.component.html
ersetzen Sie den Abschnitt <nav>
durch Folgendes:
<nav class="nav nav-pills"> <a class="nav-link" routerLink="todos" routerLinkActive="active" *ngIf="auth.loggedIn">Todo List</a> <a class="nav-link" routerLink="users" routerLinkActive="active" *ngIf="auth.loggedIn">Users</a> <a class="nav-link" routerLink="login" routerLinkActive="active" *ngIf="!auth.loggedIn">Login</a> <a class="nav-link" (click)="logout()" href="#" *ngIf="auth.loggedIn">Logout</a> </nav>
Wir haben unsere Navigation kontextbewusst gemacht, dass sie nur bestimmte Elemente anzeigen soll, je nachdem, ob der Benutzer eingeloggt ist oder nicht. auth.loggedIn
kann natürlich überall verwendet werden, wo Sie den Authentifizierungsdienst importieren können.
Sichern der API
Sie denken vielleicht, das ist großartig … alles scheint wunderbar zu funktionieren . Aber versuchen Sie, sich mit allen drei der verschiedenen Benutzernamen anzumelden, und Sie werden etwas bemerken: Sie alle geben dieselbe Todo-Liste zurück. Wenn wir uns unseren API-Server ansehen, können wir sehen, dass jeder Benutzer tatsächlich seine eigene Liste von Elementen hat, also was ist los?
Denken Sie daran, als wir anfingen, haben wir unseren API-Endpunkt /todos
so codiert, dass er immer die Aufgabenliste für userID=1
. Dies lag daran, dass wir nicht wissen konnten, wer der aktuell angemeldete Benutzer war.
Sehen wir uns jetzt an, wie einfach es ist, unsere Endpunkte zu sichern und die im JWT codierten Informationen zu verwenden, um die erforderliche Benutzeridentität bereitzustellen. Fügen Sie zunächst diese eine Zeile zu Ihrer server/app.js
-Datei direkt unter dem letzten Aufruf von app.use()
:
app.use(expressJwt({secret: 'todo-app-super-shared-secret'}).unless({path: ['/api/auth']}));
Wir verwenden die express-jwt
Middleware, sagen ihr, was das gemeinsame Geheimnis ist, und geben ein Array von Pfaden an, für die kein JWT erforderlich sein sollte. Und das ist es. Sie müssen nicht jeden einzelnen Endpunkt anfassen, überall if
-Anweisungen erstellen oder ähnliches.
Intern trifft die Middleware einige Annahmen. Beispielsweise wird davon ausgegangen, dass der Authorization
-HTTP-Header dem allgemeinen JWT-Muster von Bearer {token}
folgt. (Die Bibliothek bietet jedoch viele Optionen zum Anpassen ihrer Funktionsweise, falls dies nicht der Fall ist. Weitere Informationen finden Sie unter Verwendung von express-jwt.)
Unser zweites Ziel ist es, die JWT-codierten Informationen zu verwenden, um herauszufinden, wer den Anruf tätigt. Wieder einmal kommt express-jwt
zu Hilfe. Als Teil des Lesens und Verifizierens des Tokens setzt es die verschlüsselte Nutzlast, die wir beim Signieren an die Variable req.user
in Express gesendet haben. Wir können es dann verwenden, um sofort auf jede der von uns gespeicherten Variablen zuzugreifen. In unserem Fall setzen wir userID
gleich der ID des authentifizierten Benutzers und können sie daher direkt als req.user.userID
.
Aktualisieren server/app.js
erneut und ändern Sie den /todos
-Endpunkt wie folgt:
res.send(getTodos(req.user.userID));
Und das ist es. Unsere API ist jetzt gegen unbefugten Zugriff gesichert, und wir können sicher feststellen, wer unser authentifizierter Benutzer an jedem Endpunkt ist. Unsere Client-Anwendung hat auch einen einfachen Authentifizierungsprozess, und alle von uns geschriebenen HTTP-Dienste, die unseren API-Endpunkt aufrufen, haben automatisch ein Authentifizierungstoken angehängt.
Wenn Sie das Github-Repository geklont haben und einfach das Endergebnis in Aktion sehen möchten, können Sie den Code in seiner endgültigen Form auschecken mit:
git checkout with-jwt
Ich hoffe, Sie fanden diese exemplarische Vorgehensweise hilfreich, um Ihren eigenen Angular-Apps die JWT-Authentifizierung hinzuzufügen. Danke fürs Lesen!