jagd-apps/nachsuche/backend/middleware/auth.js

83 lines
2.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const jwt = require('jsonwebtoken');
const config = require('../config/env');
// Verifiziert das Token und stellt sicher, dass es sich um ein Admin-Token handelt.
const authenticateToken = (req, res, next) => {
// Try to get token from cookie first (new secure method)
let token = req.cookies?.token;
// Fallback: Check Authorization header for backward compatibility
if (!token) {
const authHeader = req.headers['authorization'];
token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
}
if (!token) {
return res.status(401).json({
success: false,
message: 'Zugriff verweigert. Kein Token bereitgestellt.'
});
}
try {
const decoded = jwt.verify(token, config.jwtSecret);
// Reject tokens issued by a different app (C-01 cross-app auth fix)
if (decoded.app && decoded.app !== config.appName) {
return res.status(403).json({
success: false,
message: 'Ungültiger oder abgelaufener Token.'
});
}
// Rollenprüfung. Handler-Tokens werden mit demselben Secret signiert; die
// app-Prüfung oben greift bei ihnen nicht, weil sie keinen app-Claim tragen.
// Ohne diese Zeilen kann ein eingeloggter Hundeführer seinen Bearer-Token
// gegen /api/users, /api/config und /api/audit-logs schicken und hat volle
// Admin-Rechte. Tokens ohne role stammen aus der Zeit davor und wurden
// ausschließlich für Admins ausgestellt.
if (decoded.role && decoded.role !== 'admin') {
return res.status(403).json({
success: false,
message: 'Zugriff verweigert. Keine Administratorrechte.'
});
}
req.user = decoded;
next();
} catch (error) {
return res.status(403).json({
success: false,
message: 'Ungültiger oder abgelaufener Token.'
});
}
};
// Wie authenticateToken, blockiert aber nicht: setzt req.user wenn ein gültiges
// Admin-Token vorliegt und ruft ansonsten einfach next(). Für Endpunkte wie
// /logout, die auch mit abgelaufenem Token funktionieren müssen.
const attachUserIfPresent = (req, res, next) => {
let token = req.cookies?.token;
if (!token) {
const authHeader = req.headers['authorization'];
token = authHeader && authHeader.split(' ')[1];
}
if (token) {
try {
const decoded = jwt.verify(token, config.jwtSecret);
const appOk = !decoded.app || decoded.app === config.appName;
const roleOk = !decoded.role || decoded.role === 'admin';
if (appOk && roleOk) {
req.user = decoded;
}
} catch (error) {
// Ungültiges Token ist hier kein Fehler der Aufrufer wird ohne req.user bedient.
}
}
next();
};
module.exports = { authenticateToken, attachUserIfPresent };