the-tip-top-backend/src/middleware/auth.js
2025-11-17 23:47:54 +01:00

118 lines
3.2 KiB
JavaScript

/**
* 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();
}
};