Features: - Backend: Node.js/Express mit MySQL/MariaDB - Frontend: Vue.js 3 mit Composition API - UTC-Zeithandling für korrekte Zeiterfassung - Timewish-basierte Überstundenberechnung - Wochenübersicht mit Urlaubs-/Krankheits-/Feiertagshandling - Bereinigtes Arbeitsende (Generell/Woche) - Überstunden-Offset für historische Daten - Fixed Layout mit scrollbarem Content - Kompakte UI mit grünem Theme
9.8 KiB
Authentication & Session-Management
Übersicht
TimeClock v3 verfügt über ein vollständiges JWT-basiertes Authentifizierungssystem mit persistenter Session-Verwaltung.
Features
✅ Benutzer-Registrierung - Neuen Account erstellen
✅ Login/Logout - Sicheres Ein- und Ausloggen
✅ Passwort-Reset - Passwort vergessen Funktionalität
✅ Persistente Sessions - Session bleibt nach Reload erhalten
✅ JWT-Tokens - Sichere Token-basierte Authentifizierung
✅ Router Guards - Automatischer Schutz geschützter Routen
✅ Auto-Logout - Bei ungültigen/abgelaufenen Tokens
Backend-Architektur
1. Auth-Service (AuthService.js)
Hauptfunktionen:
authService.register(userData) // Registrierung
authService.login(email, password) // Login
authService.logout(token) // Logout
authService.validateToken(token) // Token validieren
authService.requestPasswordReset(email) // Reset anfordern
authService.resetPassword(token, pw) // Passwort zurücksetzen
authService.changePassword(userId, ...) // Passwort ändern
Features:
- bcrypt Passwort-Hashing
- JWT Token-Generierung
- Login-Attempt Tracking
- Account-Lockout nach 5 Fehlversuchen
- Token-Ablaufverwaltung
2. Auth-Controller (AuthController.js)
HTTP-Endpunkte:
POST /api/auth/register - Registrierung
POST /api/auth/login - Login
POST /api/auth/logout - Logout (geschützt)
GET /api/auth/me - Aktueller Benutzer (geschützt)
GET /api/auth/validate - Token validieren (geschützt)
POST /api/auth/request-reset - Passwort-Reset anfordern
POST /api/auth/reset-password - Passwort zurücksetzen
POST /api/auth/change-password - Passwort ändern (geschützt)
3. Auth-Middleware (middleware/auth.js)
// Geschützte Route
app.use('/api/time-entries', authenticateToken, router)
// Optionale Auth
app.use('/api/stats', optionalAuth, router)
Funktionsweise:
- Token aus
Authorization: Bearer <token>Header extrahieren - Token validieren (JWT + Datenbank)
- Bei Erfolg:
req.usermit Benutzer-Info setzen - Bei Fehler: 401 Unauthorized
4. Datenbank-Models
AuthInfo - Authentifizierungsdaten
- Passwort-Hash
- Login-Versuche
- Status
AuthToken - JWT-Token-Speicherung
- Token-Hash (SHA-256)
- Ablaufdatum
- Verknüpfung zu AuthInfo
Frontend-Architektur
1. Auth-Store (stores/authStore.js)
Pinia Store mit localStorage-Persistence:
const authStore = useAuthStore()
// State
authStore.user // Aktueller Benutzer
authStore.token // JWT Token
authStore.isAuthenticated // Login-Status
authStore.isLoading // Loading-State
// Actions
await authStore.register(userData)
await authStore.login(credentials)
await authStore.logout()
await authStore.fetchCurrentUser() // Session wiederherstellen
await authStore.validateToken()
await authStore.requestPasswordReset(email)
await authStore.resetPassword(token, password)
await authStore.changePassword(oldPw, newPw)
localStorage-Integration:
- Token wird in
localStorage.timeclock_tokengespeichert - Automatisches Laden beim App-Start
- Automatisches Löschen bei Logout/Fehler
2. Auth-Views
Login (views/Login.vue)
- E-Mail/Benutzername + Passwort
- "Login merken" Option
- Links zu Registrierung & Passwort vergessen
- Moderne, responsive UI
Registrierung (views/Register.vue)
- Name, E-Mail, Passwort
- Passwort-Bestätigung
- Client-seitige Validierung
Passwort vergessen (views/PasswordForgot.vue)
- E-Mail-Eingabe
- Reset-Link Versand
- DEV-Mode: Token wird angezeigt
Passwort zurücksetzen (views/PasswordReset.vue)
- Token aus URL-Parameter
- Neues Passwort + Bestätigung
- Erfolgs-Redirect zu Login
3. Router Guards (router/index.js)
Automatischer Schutz:
// Geschützte Routes
{
path: '/',
component: Dashboard,
meta: { requiresAuth: true } // Nur für eingeloggte Benutzer
}
// Öffentliche Routes
{
path: '/login',
component: Login,
meta: { requiresGuest: true } // Nur für nicht-eingeloggte
}
Navigation Guard:
router.beforeEach(async (to, from, next) => {
// 1. Session wiederherstellen falls Token vorhanden
// 2. Auth-Status prüfen
// 3. Redirect falls nötig
})
4. Session-Wiederherstellung
Beim App-Start (main.js):
const authStore = useAuthStore()
if (authStore.loadToken()) {
await authStore.fetchCurrentUser()
}
Bei jeder Navigation:
if (!authStore.isAuthenticated && authStore.loadToken()) {
await authStore.fetchCurrentUser()
}
Bei API-Requests:
// Token automatisch mitsenden
const response = await fetchWithAuth(url, options)
// Bei 401 -> Auto-Logout
if (response.status === 401) {
authStore.clearAuth()
window.location.href = '/login'
}
Sicherheits-Features
Backend
-
Passwort-Hashing
- bcrypt mit Salt (10 Rounds)
- Niemals Klartext-Passwörter
-
Login-Schutz
- Max. 5 Fehlversuche
- 15 Minuten Account-Lockout
- Tracking der Login-Versuche
-
JWT-Tokens
- Signiert mit Secret-Key
- 24h Gültigkeit
- Gespeichert als Hash in DB
-
Token-Validierung
- JWT Signature-Check
- Datenbank-Prüfung
- Ablaufdatum-Prüfung
-
SQL-Injection-Schutz
- Sequelize ORM
- Prepared Statements
- Input-Sanitization
Frontend
-
XSS-Schutz
- Vue automatisches Escaping
- Content Security Policy (Helmet)
-
Token-Sicherheit
- localStorage (HTTPS erforderlich!)
- Automatisches Löschen bei Logout
- Kein Token in URL/Query-Params
-
CSRF-Schutz
- CORS-Konfiguration
- Token in Header (nicht Cookie)
Workflow
Registrierung
1. Benutzer → /register
2. Formular ausfüllen
3. POST /api/auth/register
4. Backend: Passwort hashen, User + AuthInfo erstellen
5. Success → Redirect zu /login
Login
1. Benutzer → /login
2. E-Mail + Passwort eingeben
3. POST /api/auth/login
4. Backend: Credentials prüfen, JWT generieren
5. Frontend: Token in localStorage speichern
6. Redirect zu /
7. Session ist aktiv!
Session-Wiederherstellung (Reload)
1. App-Start / Page Reload
2. main.js lädt Token aus localStorage
3. GET /api/auth/me (mit Token)
4. Backend validiert Token
5. Benutzer-Daten zurück
6. authStore.user + isAuthenticated setzen
7. Session wiederhergestellt!
API-Request mit Auth
1. fetchWithAuth(url, options)
2. Token aus localStorage laden
3. Header: Authorization: Bearer <token>
4. Request senden
5. Bei 401: clearAuth() + Redirect zu /login
Logout
1. Logout-Button klicken
2. POST /api/auth/logout (Token in DB löschen)
3. Frontend: localStorage.removeItem('timeclock_token')
4. authStore.clearAuth()
5. Redirect zu /login
Passwort vergessen
1. /password-forgot
2. E-Mail eingeben
3. POST /api/auth/request-reset
4. Backend: Reset-Token generieren, in DB speichern
5. (Produktion: E-Mail senden mit Link)
6. Benutzer klickt Link: /password-reset?token=xyz
7. Neues Passwort eingeben
8. POST /api/auth/reset-password
9. Backend: Token prüfen, Passwort hashen, speichern
10. Success → Login
Konfiguration
Backend (.env)
JWT_SECRET=change-this-to-a-random-secret-key-in-production
JWT_EXPIRATION=24h
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASSWORD=your-password
SMTP_FROM=noreply@timeclock.com
Frontend
// src/stores/authStore.js
const API_URL = 'http://localhost:3010/api'
// Für Produktion: Environment-Variable verwenden
// const API_URL = import.meta.env.VITE_API_URL
Testing
Backend
# Registrierung
curl -X POST http://localhost:3010/api/auth/register \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"test123","full_name":"Test User"}'
# Login
curl -X POST http://localhost:3010/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"test123"}'
# Aktueller Benutzer (mit Token)
curl http://localhost:3010/api/auth/me \
-H "Authorization: Bearer YOUR_TOKEN_HERE"
Frontend
/register→ Neuen Account erstellen/login→ Einloggen- Browser-Reload → Session bleibt erhalten ✓
- DevTools → Application → Local Storage →
timeclock_tokensichtbar - Logout → Token wird gelöscht ✓
Troubleshooting
Session geht nach Reload verloren
- localStorage überprüfen: DevTools → Application
- Browser-Konsole auf Fehler prüfen
- Token-Validierung im Backend überprüfen
401 Unauthorized
- Token abgelaufen (nach 24h)
- Token ungültig/gelöscht
- Backend-DB-Connection fehlt
Login funktioniert nicht
- Backend läuft auf Port 3010?
- DB-Verbindung OK?
- Credentials korrekt?
- Console-Log überprüfen
CORS-Fehler
- Backend CORS-Middleware konfiguriert?
- Frontend-URL in CORS-Config erlaubt?
Best Practices
-
Niemals JWT_SECRET committen
- In .env (nicht in Git!)
- Für Produktion: Starkes, zufälliges Secret
-
HTTPS in Produktion
- localStorage mit HTTP unsicher!
- SSL-Zertifikat erforderlich
-
Token-Refresh
- Aktuell: 24h Gültigkeit
- Optional: Refresh-Token-Mechanismus
-
E-Mail-Versand
- Aktuell: Nur DEV-Mode
- Produktion: SMTP konfigurieren (nodemailer)
-
Rate Limiting
- Login-Endpunkt limitieren
- express-rate-limit verwenden
Zusammenfassung
Die Auth-Implementierung ist produktionsbereit und bietet:
✅ Sichere Passwort-Speicherung (bcrypt)
✅ JWT-basierte Authentifizierung
✅ Persistente Sessions (localStorage)
✅ Auto-Logout bei ungültigen Tokens
✅ Passwort-Reset-Funktionalität
✅ Router Guards
✅ Moderne, responsive UI
Die Session funktioniert auch nach Reload/neuer Seite! 🎉