d3718da1f8
Passkey-Login analog zu werte-next: auf der Login-Seite "Mit Passkey anmelden", Verwaltung der eigenen Passkeys im neuen Tab Einstellungen. Das Passwort bleibt als Alternative bestehen. - lib/webauthn.ts, lib/passkeys.ts sowie API-Routen unter /api/passkey - proxy.ts: /api/passkey/authenticate ohne Session erreichbar - TabLayout: dritter Tab Einstellungen (Index-Tabs statt Route wie werte) - RP-Konfiguration ueber AUSGABEN_RP_*, da sich die .env auf dem Server mit anderen Apps teilt, die RP_ID/RP_ORIGIN bereits belegen - Eigene Tabelle ausgaben_passkeys aus demselben Grund: werte-next nutzt in der gemeinsamen Datenbank RXF bereits die Tabelle passkeys - eslint.config.mjs auf die Flat-Config von eslint-config-next umgestellt Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
204 lines
6.3 KiB
Markdown
204 lines
6.3 KiB
Markdown
# Wiederverwendbare Authentifizierung
|
|
|
|
Diese Authentifizierungslösung kann einfach in andere Next.js Projekte übernommen werden.
|
|
|
|
## Komponenten
|
|
|
|
### 1. Core Libraries (wiederverwendbar)
|
|
- `/lib/auth.ts` - Authentifizierungslogik (Benutzerverwaltung über .env)
|
|
- `/lib/session.ts` - JWT-basiertes Session-Management
|
|
- `/middleware.ts` - Route-Schutz Middleware
|
|
- `/lib/webauthn.ts` - Passkey-Logik (Registrierung & Anmeldung, WebAuthn)
|
|
- `/lib/passkeys.ts` - Datenbankzugriff auf die Tabelle `ausgaben_passkeys`
|
|
|
|
### 2. UI Komponenten (wiederverwendbar)
|
|
- `/app/login/page.tsx` - Login-Seite (Passwort + „Mit Passkey anmelden")
|
|
- `/app/login/actions.ts` - Server Actions für Login/Logout
|
|
- `/components/LogoutButton.tsx` - Logout-Button Komponente
|
|
- `/components/Passkeys.tsx` - Verwaltung der eigenen Passkeys (Tab *Einstellungen*)
|
|
|
|
### 3. API-Routen (Passkeys)
|
|
- `/app/api/passkey/route.ts` - eigene Passkeys auflisten (GET) / löschen (DELETE)
|
|
- `/app/api/passkey/register/route.ts` - Passkey registrieren (Session erforderlich)
|
|
- `/app/api/passkey/authenticate/route.ts` - Anmeldung per Passkey (öffentlich)
|
|
|
|
## Installation in neuen Projekten
|
|
|
|
### 1. Dependencies installieren
|
|
```bash
|
|
npm install jose bcryptjs
|
|
npm install --save-dev @types/bcryptjs
|
|
|
|
# Für Passkeys (WebAuthn):
|
|
npm install @simplewebauthn/server @simplewebauthn/browser
|
|
```
|
|
|
|
### 2. Dateien kopieren
|
|
Kopiere folgende Dateien in dein neues Projekt:
|
|
- `lib/auth.ts`
|
|
- `lib/session.ts`
|
|
- `middleware.ts`
|
|
- `app/login/` (gesamter Ordner)
|
|
- `scripts/generate-password.js` (Passwort-Hash Generator)
|
|
- `components/LogoutButton.tsx` (optional)
|
|
|
|
### 3. Passwort-Hashes generieren
|
|
Verwende das mitgelieferte Script, um sichere Passwort-Hashes zu erstellen:
|
|
|
|
```bash
|
|
# Interactive Mode
|
|
node scripts/generate-password.js
|
|
|
|
# Mit Passwort als Argument
|
|
node scripts/generate-password.js meinPasswort123
|
|
```
|
|
|
|
Das Script gibt einen bcrypt-Hash aus, den du in der `.env` verwenden kannst.
|
|
|
|
### 4. Umgebungsvariablen einrichten
|
|
Füge zu deiner `.env` hinzu:
|
|
|
|
```env
|
|
# Authentifizierung
|
|
# Format: username:passwordHash,username2:passwordHash2
|
|
# Verwende 'node scripts/generate-password.js' um Hashes zu generieren
|
|
AUTH_USERS=admin:$2b$10$DKLO7uQPmdAw9Z64NChro...,user1:$2b$10$K613Z70Hodr6xyEh10Mw2u...
|
|
|
|
# Secret Key für JWT (unbedingt ändern in Production!)
|
|
AUTH_SECRET=your-super-secret-key-change-this
|
|
|
|
# Passkeys (WebAuthn) — RP_ID = nur der Host, RP_ORIGIN = volle URL
|
|
RP_ID=ausgaben.fuerst-stuttgart.de
|
|
RP_ORIGIN=https://ausgaben.fuerst-stuttgart.de
|
|
RP_NAME=Ausgaben-Log
|
|
```
|
|
|
|
### 5. Logout-Button einbinden (optional)
|
|
```tsx
|
|
import LogoutButton from '@/components/LogoutButton';
|
|
|
|
// In deiner Komponente:
|
|
<LogoutButton />
|
|
```
|
|
|
|
## Konfiguration
|
|
|
|
### Benutzer hinzufügen/entfernen
|
|
|
|
1. Generiere einen Passwort-Hash:
|
|
```bash
|
|
node scripts/generate-password.js neuesPasswort
|
|
```
|
|
|
|
2. Editiere die `AUTH_USERS` Variable in der `.env`:
|
|
```env
|
|
AUTH_USERS=user1:$2b$10$hash1...,user2:$2b$10$hash2...,user3:$2b$10$hash3...
|
|
```
|
|
|
|
### Authentifizierung deaktivieren
|
|
Entferne die `AUTH_USERS` Variable oder setze sie auf einen leeren String:
|
|
```env
|
|
AUTH_USERS=
|
|
```
|
|
|
|
### Session-Dauer anpassen
|
|
Editiere in `lib/session.ts`:
|
|
```ts
|
|
const SESSION_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 Tage
|
|
```
|
|
|
|
### Geschützte Routen anpassen
|
|
Editiere in `middleware.ts` die `publicPaths`:
|
|
```ts
|
|
const publicPaths = ['/login', '/api/passkey/authenticate', '/public-page'];
|
|
```
|
|
Die Passkey-Anmeldung muss ohne Session erreichbar sein.
|
|
|
|
### Passkeys verwalten
|
|
- **Registrieren**: angemeldet im Tab *Einstellungen* → „Passkey hinzufügen".
|
|
- **Anmelden**: auf der Login-Seite „Mit Passkey anmelden".
|
|
- **Speicherung**: Tabelle `ausgaben_passkeys` (siehe `create_table.sql`), wird beim
|
|
ersten Zugriff automatisch angelegt, sofern der DB-Benutzer CREATE-Rechte hat.
|
|
**Wichtig bei Übernahme in ein anderes Projekt**: Teilen sich mehrere Apps eine
|
|
Datenbank, braucht jede App einen eigenen Tabellennamen (`TABLE` in
|
|
`lib/passkeys.ts`) — sonst sehen und löschen sie gegenseitig ihre Passkeys.
|
|
- `RP_ID` muss exakt dem Hostnamen entsprechen (ohne Protokoll/Port). Ändert sich
|
|
`RP_ID`, werden bereits registrierte Passkeys ungültig.
|
|
- WebAuthn funktioniert nur über **HTTPS** oder auf `localhost`.
|
|
|
|
## Sicherheitshinweise
|
|
|
|
1. **AUTH_SECRET ändern**: Verwende in Production einen starken, zufälligen Schlüssel
|
|
2. **HTTPS verwenden**: In Production immer HTTPS aktivieren
|
|
3. **Passwort-Hashing**: Passwörter werden mit bcrypt gehashed (10 Salt Rounds)
|
|
4. **Keine Klartext-Passwörter**: Verwende immer das Script zur Hash-Generierung
|
|
|
|
## Passwort-Hash Generator
|
|
|
|
Das Script `scripts/generate-password.js` verwendet bcrypt mit 10 Salt Rounds, um sichere Passwort-Hashes zu erstellen.
|
|
|
|
### Verwendung
|
|
|
|
Interactive Mode (empfohlen für sensible Passwörter):
|
|
```bash
|
|
npm run generate-password
|
|
# oder
|
|
node scripts/generate-password.js
|
|
# Passwort wird interaktiv abgefragt
|
|
```
|
|
|
|
Mit Argument:
|
|
```bash
|
|
npm run generate-password -- meinPasswort
|
|
# oder
|
|
node scripts/generate-password.js meinPasswort
|
|
```
|
|
|
|
### Ausgabe
|
|
```
|
|
🔐 Generiere Passwort-Hash...
|
|
|
|
✅ Hash generiert:
|
|
────────────────────────────────────────────────────────────────────────────────
|
|
$2b$10$DKLO7uQPmdAw9Z64NChro.8mOsnqZQaRZjctWDojIkK926ROBVyJW
|
|
────────────────────────────────────────────────────────────────────────────────
|
|
|
|
📝 Verwende diesen Hash in der .env Datei:
|
|
AUTH_USERS=username:$2b$10$DKLO7uQPmdAw9Z64NChro.8mOsnqZQaRZjctWDojIkK926ROBVyJW
|
|
```
|
|
|
|
## Erweiterte Verwendung
|
|
|
|
### Session-Informationen abrufen
|
|
```ts
|
|
import { getSession } from '@/lib/session';
|
|
|
|
const session = await getSession();
|
|
if (session) {
|
|
console.log('Eingeloggt als:', session.username);
|
|
}
|
|
```
|
|
|
|
### Programmatisch prüfen, ob authentifiziert
|
|
```ts
|
|
import { isAuthenticated } from '@/lib/session';
|
|
|
|
const authenticated = await isAuthenticated();
|
|
```
|
|
|
|
### In Server Components
|
|
```tsx
|
|
import { getSession } from '@/lib/session';
|
|
import { redirect } from 'next/navigation';
|
|
|
|
export default async function ProtectedPage() {
|
|
const session = await getSession();
|
|
|
|
if (!session) {
|
|
redirect('/login');
|
|
}
|
|
|
|
return <div>Hallo {session.username}!</div>;
|
|
}
|
|
```
|