JWT-Laufzeit (JWT_EXPIRES_IN) standardmaessig auf 7d gesetzt, damit Benutzer nicht mehr taeglich neu anmelden muessen. Doku (Betrieb, Benutzeranleitung, Glossar) und .env.example angepasst. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
63 lines
2.0 KiB
JavaScript
63 lines
2.0 KiB
JavaScript
import jwt from 'jsonwebtoken';
|
|
import { pool } from '../db.js';
|
|
|
|
function secret() {
|
|
const value = process.env.JWT_SECRET;
|
|
if (!value || value.length < 16) {
|
|
throw new Error('JWT_SECRET fehlt oder ist zu kurz (min. 16 Zeichen).');
|
|
}
|
|
return value;
|
|
}
|
|
|
|
export function signToken(user) {
|
|
return jwt.sign({ sub: user.id, role: user.role }, secret(), {
|
|
expiresIn: process.env.JWT_EXPIRES_IN || '7d',
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Prueft das Bearer-Token und laedt den aktuellen Benutzer aus der Datenbank.
|
|
*
|
|
* Die Spaltenliste ist bewusst vollstaendig aufgezaehlt und kein SELECT *:
|
|
* das Passwort-Hash soll nicht am Request haengen. Sie muss aber alles
|
|
* enthalten, was publicUser() ausliefert - sonst faellt beim Neuladen z. B.
|
|
* die Theme-Wahl auf "nichts gewaehlt" zurueck.
|
|
*/
|
|
export async function requireAuth(req, res, next) {
|
|
const header = req.headers.authorization || '';
|
|
const token = header.startsWith('Bearer ') ? header.slice(7) : null;
|
|
if (!token) return res.status(401).json({ error: 'Nicht angemeldet.' });
|
|
|
|
let payload;
|
|
try {
|
|
payload = jwt.verify(token, secret());
|
|
} catch {
|
|
return res.status(401).json({ error: 'Sitzung abgelaufen. Bitte neu anmelden.' });
|
|
}
|
|
|
|
try {
|
|
const [rows] = await pool.query(
|
|
`SELECT id, username, email, name, role, color, avatar, theme, theme_mode,
|
|
is_active, created_at, updated_at
|
|
FROM icon_users WHERE id = ? LIMIT 1`,
|
|
[payload.sub]
|
|
);
|
|
const user = rows[0];
|
|
if (!user) return res.status(401).json({ error: 'Benutzer existiert nicht mehr.' });
|
|
if (!user.is_active) return res.status(403).json({ error: 'Benutzerkonto ist deaktiviert.' });
|
|
|
|
req.user = { ...user, is_active: Boolean(user.is_active) };
|
|
next();
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
}
|
|
|
|
/** Nur Rolle admin - schuetzt Einstellungen und Nutzerverwaltung. */
|
|
export function requireAdmin(req, res, next) {
|
|
if (req.user?.role !== 'admin') {
|
|
return res.status(403).json({ error: 'Diese Aktion ist Administratoren vorbehalten.' });
|
|
}
|
|
next();
|
|
}
|