/** * Middleware d'authentification JWT */ import jwt from 'jsonwebtoken'; import { pool } from '../../db.js'; import { AppError } from './errorHandler.js'; /** * Vérifie le token JWT et ajoute l'utilisateur à req.user */ export const authenticateToken = async (req, res, next) => { try { // Récupérer le token depuis le header Authorization const authHeader = req.headers.authorization; const token = authHeader && authHeader.split(' ')[1]; // Format: "Bearer TOKEN" if (!token) { return next(new AppError('Token manquant. Veuillez vous authentifier.', 401)); } // Vérifier et décoder le token const decoded = jwt.verify(token, process.env.JWT_SECRET); // Récupérer l'utilisateur depuis la base de données const result = await pool.query( 'SELECT id, email, role, first_name, last_name, is_verified FROM users WHERE id = $1', [decoded.userId] ); if (result.rows.length === 0) { return next(new AppError('Utilisateur non trouvé', 401)); } const user = result.rows[0]; // Vérifier que l'email est vérifié (optionnel selon vos besoins) // if (!user.is_verified) { // return next(new AppError('Email non vérifié. Veuillez vérifier votre email.', 403)); // } // Ajouter l'utilisateur à la requête req.user = { id: user.id, email: user.email, role: user.role, firstName: user.first_name, lastName: user.last_name, isVerified: user.is_verified, }; next(); } catch (error) { if (error.name === 'JsonWebTokenError') { return next(new AppError('Token invalide', 403)); } if (error.name === 'TokenExpiredError') { return next(new AppError('Token expiré', 403)); } return next(error); } }; /** * Vérifie que l'utilisateur a l'un des rôles autorisés * @param {...string} roles - Liste des rôles autorisés */ export const authorizeRoles = (...roles) => { return (req, res, next) => { if (!req.user) { return next(new AppError('Utilisateur non authentifié', 401)); } if (!roles.includes(req.user.role)) { return next( new AppError(`Accès refusé. Rôle requis: ${roles.join(' ou ')}`, 403) ); } next(); }; }; /** * Middleware optionnel qui n'échoue pas si le token est absent * Utile pour les routes qui peuvent fonctionner avec ou sans authentification */ export const optionalAuth = async (req, res, next) => { try { const authHeader = req.headers.authorization; const token = authHeader && authHeader.split(' ')[1]; if (!token) { return next(); // Continuer sans utilisateur } const decoded = jwt.verify(token, process.env.JWT_SECRET); const result = await pool.query( 'SELECT id, email, role, first_name, last_name FROM users WHERE id = $1', [decoded.userId] ); if (result.rows.length > 0) { req.user = { id: result.rows[0].id, email: result.rows[0].email, role: result.rows[0].role, firstName: result.rows[0].first_name, lastName: result.rows[0].last_name, }; } next(); } catch (error) { // En cas d'erreur, on continue quand même sans utilisateur next(); } };