Next.js JWT Auth einfach gemacht: Vom Setup bis zur Bereitstellung
Emily Parker
Product Engineer · Leapcell

Implementierung von Authentifizierung und Autorisierung mit JWT-Middleware in Next.js: Von Grundlagen bis zur praktischen Anwendung
I. Einführung: Warum JWT für die Authentifizierung wählen?
In der modernen Webentwicklung sind Benutzerauthentifizierung und -autorisierung Kernaspekte beim Erstellen sicherer Anwendungen. JSON Web Token (JWT) hat sich mit seinen zustandslosen, plattformübergreifenden und leichtgewichtigen Eigenschaften zu einer der gängigsten Authentifizierungslösungen in Front-End- und Back-End-getrennten Anwendungen entwickelt. Als das beliebteste Full-Stack-Framework im React-Ökosystem bietet Next.js einen leistungsstarken Middleware-Mechanismus, der die Anfrageabfangung und den Routenschutz effizient implementieren kann. Dieser Artikel befasst sich eingehend damit, wie man die Benutzerauthentifizierung in Next.js durch benutzerdefinierte Middleware in Kombination mit JWT erreicht, um sicherzustellen, dass die Anfragen gültige userid
und username
enthalten, und deckt den gesamten Prozess von grundlegenden Prinzipien bis hin zu Praktiken auf Produktionsniveau ab.
II. JWT-Grundlagen: Kernkonzepte und Funktionsprinzipien
2.1 JWT-Strukturanalyse
JWT besteht aus drei Teilen, die durch .
getrennt sind:
- Header: Enthält den Token-Typ (JWT) und den Signaturalgorithmus (z. B. HMAC SHA256, RSA).
{ "alg": "HS256", "typ": "JWT" }
- Payload: Speichert Benutzerinformationen (nicht sensible Daten) und Metadaten (z. B. die Ablaufzeit
exp
).{ "sub": "1234567890", // Eindeutige Benutzerkennung (userid) "name": "John Doe", // Benutzername (username) "iat": 1687756800, // Ausgestellt am "exp": 1687760400 // Ablaufzeit (1 Stunde später) }
- Signatur: Signiert Header und Payload mit dem im Header angegebenen Algorithmus, um sicherzustellen, dass das Token nicht manipuliert wurde.
2.2 Authentifizierungsprozess
- Login-Phase: Der Benutzer sendet Anmeldeinformationen (Benutzername/Passwort). Nach erfolgreicher Überprüfung durch den Server generiert dieser ein JWT und gibt es an den Client zurück.
- Token-Speicherung: Der Client speichert das JWT in einem
HttpOnly
-Cookie oder im lokalen Speicher (Cookies werden empfohlen, um XSS-Angriffe zu vermeiden). - Anfrageabfangung: Jede nachfolgende Anfrage überträgt das JWT (normalerweise im
Authorization
-Header oder Cookie). Der Server überprüft die Gültigkeit des Tokens über Middleware. - Autorisierungsentscheidung: Nach erfolgreicher Überprüfung werden die
userid
undusername
für die Berechtigungsprüfung oder Datenfilterung analysiert.
III. Next.js-Middleware: Kernmechanismen und Vorteile
3.1 Middleware-Typen
Next.js 13+ führt ein neues Middleware-System ein, das zwei Modi unterstützt:
- Globale Middleware: Wirkt sich auf alle Routen aus (mit Ausnahme von Routen, die mit dem
middleware-exclude
-Muster übereinstimmen). - Routen-Middleware: Wirkt sich nur auf bestimmte Routen oder Routengruppen aus (definiert durch Dateispeicherort oder Konfiguration).
3.2 Kernfunktionen
- Anfrageabfangung: Bevor die Anfrage die Seite oder API-Route erreicht, ändern Sie die Anfrageheader, analysieren Sie Cookies und überprüfen Sie die Identität.
- Antwortsteuerung: Geben Sie je nach Authentifizierungsergebnis eine Weiterleitungsantwort zurück (z. B. Weiterleitung zur Anmeldeseite, wenn nicht authentifiziert).
- Edge-Ausführung: Unterstützt die Ausführung im Vercel Edge Network, um eine Authentifizierung mit geringer Latenz zu erreichen (vermeiden Sie die Verwendung von Node.js-spezifischen APIs).
3.3 Middleware-Dateistruktur
Erstellen Sie middleware.ts
(TypeScript) oder middleware.js
im Stammverzeichnis des Projekts und exportieren Sie eine asynchrone Funktion, die Request
- und NextRequest
-Objekte empfängt:
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; export async function middleware(request: NextRequest) { // Authentifizierungslogik const response = NextResponse.next(); return response; } // Konfigurieren Sie den Bereich der Middleware (Beispiel: Übereinstimmung mit allen Seitenrouten) export const config = { matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'] };
IV. Projekt-Setup: Von der Initialisierung bis zur Abhängigkeitsinstallation
4.1 Erstellen Sie ein Next.js-Projekt
npx create-next-app@latest jwt-auth-demo # Wählen Sie TypeScript, App Router (Standard), ESLint (optional)
4.2 Installieren Sie Abhängigkeiten
npm install jsonwebtoken cookie @types/cookie # JWT-Verarbeitung und Cookie-Analyse npm install bcryptjs # Passwort-Hashing (wird nur serverseitig verwendet)
4.3 Umgebungskonfiguration
Erstellen Sie .env.local
im Stammverzeichnis, um den JWT-Signaturschlüssel und die Ablaufzeit zu speichern:
JWT_SECRET=your-strong-secret-key-128-bit-or-longer JWT_EXPIRES_IN=3600 # 1 Stunde (in Sekunden)
V. Implementierung der Login-Funktion: Generieren und Zurückgeben von JWT
5.1 Erstellen Sie eine Login-API-Route
Implementieren Sie die Login-Logik in app/api/auth/login/route.ts
:
import { NextResponse } from 'next/server'; import jwt from 'jsonwebtoken'; import { compare } from 'bcryptjs'; import { User } from '@/types/user'; // Benutzerdefinierter Benutzertyp // Mock-Datenbankbenutzer (müssen tatsächlich mit der Datenbank verbunden werden) const mockUsers: User[] = [ { id: '1', username: 'admin', password: '$2a$10$H6pXZpZ...' } // Gehashtes Passwort ]; export async function POST(request: Request) { const { username, password } = await request.json(); // Finde den Benutzer const user = mockUsers.find(u => u.username === username); if (!user) { return NextResponse.json({ error: 'Benutzer existiert nicht' }, { status: 401 }); } // Überprüfen Sie das Passwort const isPasswordValid = await compare(password, user.password); if (!isPasswordValid) { return NextResponse.json({ error: 'Falsches Passwort' }, { status: 401 }); } // Generieren Sie JWT const token = jwt.sign( { userId: user.id, username: user.username }, // Die Payload enthält userid und username process.env.JWT_SECRET!, { expiresIn: process.env.JWT_EXPIRES_IN } ); // Setzen Sie ein HttpOnly Cookie (Sicherheitsattribut) const response = NextResponse.json({ message: 'Login erfolgreich' }); response.cookies.set('authToken', token, { httpOnly: true, secure: process.env.NODE_ENV === 'production', // Aktivieren Sie HTTPS in der Produktionsumgebung sameSite: 'lax', // Verhindern Sie CSRF-Angriffe maxAge: Number(process.env.JWT_EXPIRES_IN), path: '/' }); return response; }
5.2 Login-Seitenkomponente
Erstellen Sie ein Login-Formular in app/login/page.tsx
:
'use client'; // Client-Komponente import { useState } from'react'; import { useRouter } from 'next/navigation'; export default function LoginPage() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const router = useRouter(); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const response = await fetch('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }) }); if (response.ok) { router.push('/dashboard'); // Weiterleitung nach erfolgreicher Anmeldung } else { const data = await response.json(); console.error(data.error); } }; return ( <form onSubmit={handleSubmit}> <input type="text" placeholder="Username" value={username} onChange={(e) => setUsername(e.target.value)} required /> <input type="password" placeholder="Password" value={password} onChange={(e) => setPassword(e.target.value)} required /> <button type="submit">Login</button> </form> ); }
VI. Implementierung der Kern-Middleware: JWT-Verifizierung und Extraktion von Benutzerinformationen
6.1 Analysieren Sie das JWT im Cookie
Erstellen Sie zunächst eine Hilfsfunktion utils/jwt.ts
, um die JWT-Überprüfung zu handhaben:
import jwt from 'jsonwebtoken'; import { Cookie } from 'cookie'; export type JwtPayload = { userId: string; username: string; iat?: number; exp?: number; }; export function parseAuthCookie(cookieHeader: string | undefined): string | null { if (!cookieHeader) return null; const cookies = Cookie.parse(cookieHeader); return cookies.authToken || null; } export function verifyJwt(token: string): JwtPayload | null { try { return jwt.verify(token, process.env.JWT_SECRET!) as JwtPayload; } catch (error) { console.error('JWT verification failed:', error); return null; } }
6.2 Schreiben Sie die Authentifizierungs-Middleware
Implementieren Sie die Kernlogik in middleware.ts
, um Anfragen abzufangen und das JWT zu überprüfen:
import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { parseAuthCookie, verifyJwt } from './utils/jwt'; export async function middleware(request: NextRequest) { // 1. Holen Sie sich das JWT aus dem Cookie const token = parseAuthCookie(request.headers.get('cookie')); // 2. Definieren Sie geschützte Routen (Beispiel: alle Seiten außer der Login-Seite) const isProtectedRoute = !request.nextUrl.pathname.startsWith('/login'); if (isProtectedRoute) { // 3. Kein Token bereitgestellt: Weiterleitung zur Login-Seite if (!token) { return NextResponse.redirect(new URL('/login', request.url)); } // 4. Überprüfen Sie das JWT const payload = verifyJwt(token); if (!payload) { // Das Token ist ungültig oder abgelaufen, löschen Sie das ungültige Cookie (optional) const response = NextResponse.redirect(new URL('/login', request.url)); response.cookies.delete('authToken'); return response; } // 5. Überprüfung bestanden: Hängen Sie Benutzerinformationen an den Anfragekontext an (optional, muss mit Routenparametern verwendet werden) // Oder holen Sie es über die getToken-Funktion in der nachfolgenden Verarbeitung ab } else { // 6. Login-Seite: Wenn authentifiziert, Weiterleitung zum Dashboard if (token && verifyJwt(token)) { return NextResponse.redirect(new URL('/dashboard', request.url)); } } // 7. Erlauben Sie, dass die Anfrage fortgesetzt wird return NextResponse.next(); } // 8. Konfigurieren Sie den Bereich der Middleware (Übereinstimmung mit allen Seiten außer API-Routen und statischen Ressourcen) export const config = { matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'] };
6.3 Analyse der Kernlogik der Middleware
- Routenschutzstrategie: Bestimmen Sie, ob eine Authentifizierung über
isProtectedRoute
erforderlich ist (ohne die Seite/login
). - Token-Existenzprüfung: Wenn kein gültiger Cookie übertragen wird, Weiterleitung zur Login-Seite.
- Signaturüberprüfung und Ablaufprüfung: Verwenden Sie die
jsonwebtoken
-Bibliothek, um das Token zu überprüfen und den Ablauf automatisch zu verarbeiten (das Feldexp
). - Sicherheitsverbesserung: Löschen Sie das Client-Cookie, wenn das Token ungültig ist, um die Wiederverwendung des abgelaufenen Tokens zu vermeiden.
- Login-Seitenoptimierung: Wenn ein authentifizierter Benutzer die Login-Seite besucht, automatische Weiterleitung zum Dashboard, um die Benutzerfreundlichkeit zu verbessern.
VII. Schutz von Routen: Abrufen von Benutzerinformationen auf Seiten
7.1 Abrufen von Benutzerinformationen in Serverkomponenten
Auf einer geschützten Seite (z. B. app/dashboard/page.tsx
) rufen Sie die userid
und username
ab, indem Sie das JWT erneut überprüfen:
import { NextResponse } from 'next/server'; import { parseAuthCookie, verifyJwt } from '@/utils/jwt'; export default async function Dashboard() { // Holen Sie sich den Cookie aus den Anfrageheadern (Serverkomponenten können auf das Anfrageobjekt zugreifen) const token = parseAuthCookie(headers.get('cookie')); const payload = token? verifyJwt(token) : null; if (!payload) { // Theoretisch hat die Middleware sie abgefangen, aber Edge-Fälle müssen behandelt werden (z. B. wenn das Token während der Anfrage abläuft) return NextResponse.redirect(new URL('/login', request.url)); } return ( <div> <h1>Willkommen, {payload.username}!</h1> <p>Benutzer-ID: {payload.userId}</p> </div> ); }
7.2 Abrufen des Authentifizierungsstatus in Clientkomponenten
Abrufen des Benutzerstatus vom Server über useEffect
oder eine Bibliothek eines Drittanbieters (z. B. SWR):
'use client'; import { useEffect, useState } from'react'; import { useRouter } from 'next/navigation'; export default function UserProfile() { const [user, setUser] = useState<{ userId: string; username: string } | null>(null); const router = useRouter(); useEffect(() => { // Der Client sendet eine Anfrage an die API-Route, um das Token zu überprüfen und Benutzerinformationen zurückzugeben const fetchUser = async () => { const response = await fetch('/api/auth/user'); if (response.ok) { const data = await response.json(); setUser(data); } else { router.push('/login'); } }; fetchUser(); }, [router]); return ( user? ( <div> <h2>Benutzerinformationen</h2> <p>Benutzername: {user.username}</p> <p>Benutzer-ID: {user.userId}</p> </div> ) : ( <p>Wird geladen...</p> ) ); }
7.3 Erstellen Sie eine API-Route für Benutzerinformationen
Stellen Sie eine Benutzeroberflächenschnittstelle in app/api/auth/user/route.ts
bereit (muss durch Middleware geschützt werden):
import { NextResponse } from 'next/server'; import { parseAuthCookie, verifyJwt } from '@/utils/jwt'; export async function GET(request: Request) { const token = parseAuthCookie(request.headers.get('cookie')); const payload = token? verifyJwt(token) : null; if (!payload) { return NextResponse.json({ error: 'Nicht authentifiziert' }, { status: 401 }); } return NextResponse.json({ userId: payload.userId, username: payload.username }); }
VIII. Abmelden: Löschen von Client-Cookies
8.1 Implementieren Sie die Logout-API-Route
Löschen Sie den authToken
-Cookie in app/api/auth/logout/route.ts
:
import { NextResponse } from 'next/server'; export async function POST(request: Request) { const response = NextResponse.redirect(new URL('/login', request.url)); response.cookies.delete('authToken', { path: '/' }); // Löschen Sie den Cookie return response; }
8.2 Abmelde-Button-Komponente
Rufen Sie die Logout-API in der Client-Komponente auf:
'use client'; import { useRouter } from 'next/navigation'; export default function LogoutButton() { const router = useRouter(); const handleLogout = async () => { await fetch('/api/auth/logout', { method: 'POST' }); router.push('/login'); }; return <button onClick={handleLogout}>Abmelden</button>; }
IX. Sicherheitsverbesserung: Best Practices in der Produktionsumgebung
9.1 Cookie-Sicherheitsattributkonfiguration
HttpOnly
: Verhindern Sie XSS-Angriffe (auf das Token kann nicht über JavaScript zugegriffen werden).Secure
: Nur in einer HTTPS-Umgebung senden (in der Produktionsumgebung obligatorisch).SameSite: 'lax'
oder'strict'
: Verhindern Sie CSRF-Angriffe (lax
ist für die meisten Szenarien geeignet, undstrict
ist strenger).Domain
undPath
: Beschränken Sie den Gültigkeitsbereich des Cookies (erlauben Sie beispielsweise nuryourdomain.com
den Zugriff).
9.2 JWT-Signierung und Ablaufstrategie
- Verwenden Sie einen Schlüssel von mindestens 256 Bit (Algorithmus
HS256
) oder eine asymmetrische RSA-Verschlüsselung (geeignet für verteilte Systeme). - Legen Sie eine kurze Ablaufzeit fest (z. B. 1 Stunde), kombiniert mit dem Refresh-Token-Mechanismus, um häufige Anmeldungen zu vermeiden.
9.3 Middleware-Leistungsoptimierung
- Edge-Middleware: Verschieben Sie nicht sensible Authentifizierungslogik (z. B. Token-Existenzprüfung) auf Edge-Knoten, um die Serverlast zu reduzieren.
- Cache-Steuerung: Überspringen Sie die Middleware-Verarbeitung für statische Ressourcen (z. B. Bilder, CSS) (ausgeschlossen über
config.matcher
).
9.4 Fehlerbehandlung und Protokollierung
- Fangen Sie JWT-Analysefehler in der Middleware ab und protokollieren Sie detaillierte Protokolle (es wird empfohlen, in der Produktionsumgebung Überwachungstools wie Sentry zu verwenden).
- Zeigen Sie dem Client allgemeine Fehlermeldungen an (z. B. "Authentifizierung fehlgeschlagen"), um die Offenlegung technischer Details zu vermeiden.
9.5 Refresh-Token-Mechanismus (Erweiterung)
- Wenn sich der Benutzer anmeldet, geben Sie sowohl das JWT als auch das Refresh-Token zurück (gespeichert in einem separaten
HttpOnly Cookie
). - Wenn das JWT abläuft, verwenden Sie das Refresh-Token, um ein neues JWT vom Server anzufordern, ohne sich erneut anmelden zu müssen.
// Refresh-Token-API-Beispiel (app/api/auth/refresh/route.ts) export async function POST(request: Request) { const refreshToken = parseAuthCookie(request.headers.get('cookie')); // Überprüfen Sie das Refresh-Token (muss in der serverseitigen Datenbank oder in Redis gespeichert werden) // Generieren Sie ein neues JWT und geben Sie es zurück }
X. Häufige Probleme und Lösungen
10.1 Die Middleware funktioniert nicht?
- Überprüfen Sie den Dateispeicherort von
middleware.ts
(er muss sich im Stammverzeichnis des Projekts befinden). - Bestätigen Sie, ob die Übereinstimmungsregeln
config.matcher
korrekt sind (verwenden Sie absolute Pfade oder reguläre Ausdrücke).
10.2 Der Cookie wird nicht in der Anfrage übertragen?
- Stellen Sie sicher, dass der
path
des während der Anmeldung festgelegten Cookies'/'
ist. - Wenn
Secure: true
in der Produktionsumgebung aktiviert ist, muss über HTTPS darauf zugegriffen werden.
10.3 Wie können Client-Komponenten Benutzerinformationen abrufen?
- Rufen Sie sie über die serverseitige API-Schnittstelle ab (z. B.
/api/auth/user
), und vermeiden Sie das direkte Analysieren von Client-Cookies (um XSS zu verhindern).
10.4 Die Token-Überprüfung schlägt in der Edge-Middleware fehl?
- Die Edge-Umgebung unterstützt keine nativen Node.js-Module. Stellen Sie sicher, dass
jsonwebtoken
eine reine JavaScript-Implementierung verwendet (z. B. die ES6-Version derjose
-Bibliothek).
XI: Sicherheitsverbesserungsmaßnahmen
-
Verwenden Sie HttpOnly + Secure Cookies
-
Legen Sie eine angemessene SameSite-Richtlinie fest
-
Die JWT-Gültigkeitsdauer sollte 2 Stunden nicht überschreiten
-
Drehen Sie die Verschlüsselungsschlüssel regelmäßig
-
Implementieren Sie CSRF-Schutz
XII. Fazit: Aufbau eines sicheren und zuverlässigen Authentifizierungssystems
Durch die Kombination von Next.js-Middleware mit JWT haben wir ein vollständiges Authentifizierungs- und Autorisierungssystem implementiert, dessen Kernvorteile Folgendes umfassen:
- Zustandslose Authentifizierung: Der Server muss keine Sitzungen speichern, wodurch hohe Parallelität und Microservice-Architekturen unterstützt werden.
- Feingranulierter Routenschutz: Konfigurieren Sie flexibel die Routen, die über
config.matcher
geschützt werden müssen. - Sicherheitsverbesserung: Verwenden Sie Cookie-Sicherheitsattribute und kurze Token-Ablaufzeiten, um die Angriffsfläche zu verringern.
- Gute Skalierbarkeit: Unterstützt das anschließende Hinzufügen von Funktionen wie rollenbasierter Zugriffssteuerung (RBAC) und Multi-Faktor-Authentifizierung (MFA).
In tatsächlichen Projekten muss die Middleware-Logik an die Geschäftsanforderungen angepasst werden (z. B. die Beurteilung des Berechtigungsniveaus), und die Einhaltung der Best Practices für die Sicherheit ist erforderlich. Der Middleware-Mechanismus von Next.js vereinfacht nicht nur den Authentifizierungsprozess, sondern bietet auch eine einheitliche Anforderungsverarbeitungsschicht für die Erstellung von Full-Stack-Anwendungen, die ein unverzichtbares Werkzeug in der modernen Webentwicklung ist.
Durch die Übung in diesem Artikel können Entwickler den gesamten Prozess von der JWT-Generierung über die Middleware-Verifizierung bis zur Extraktion von Benutzerinformationen beherrschen und so eine solide Grundlage für die Entwicklung komplexerer Authentifizierungssysteme in der Zukunft schaffen. Denken Sie immer daran: Sicherheit ist ein mehrschichtiges System. Zusätzlich zur Code-Implementierung muss es auch mit der Infrastruktur (z. B. HTTPS), Überwachungssystemen (z. B. Erkennung abnormaler Anmeldungen) und der Benutzerschulung (z. B. Richtlinien für sichere Kennwörter) kombiniert werden, um eine wirklich zuverlässige Anwendung zu erstellen.
Leapcell: Das Beste vom Serverlosen Webhosting
Schließlich möchte ich eine Plattform empfehlen, die sich am besten für die Bereitstellung von Diensten eignet: Leapcell
🚀 Erstellen Sie mit Ihrer bevorzugten Sprache
Entwickeln Sie mühelos in JavaScript, Python, Go oder Rust.
🌍 Stellen Sie unbegrenzt Projekte kostenlos bereit
Bezahlen Sie nur das, was Sie nutzen – keine Anfragen, keine Gebühren.
⚡ Pay-as-You-Go, keine versteckten Kosten
Keine Leerlaufgebühren, nur nahtlose Skalierbarkeit.
📖 Entdecken Sie unsere Dokumentation
🔹 Folgen Sie uns auf Twitter: @LeapcellHQ