const jwt = require('jsonwebtoken'); const { UsersAuth, UserProfile } = require('../models'); // JWT Secret - nên lưu trong environment variable const JWT_SECRET = process.env.JWT_SECRET || 'sena-secret-key-2026'; /** * Middleware xác thực token */ const authenticateToken = async (req, res, next) => { try { // Lấy token từ header const authHeader = req.headers.authorization; const token = authHeader && authHeader.replace('Bearer ', ''); if (!token) { return res.status(401).json({ success: false, message: 'Token không được cung cấp', }); } // Verify token const decoded = jwt.verify(token, JWT_SECRET); // Kiểm tra user còn tồn tại và session hợp lệ const user = await UsersAuth.findByPk(decoded.userId, { include: [{ model: UserProfile, as: 'profile', }], }); if (!user || !user.is_active) { return res.status(401).json({ success: false, message: 'Token không hợp lệ hoặc tài khoản đã bị vô hiệu hóa', }); } // Kiểm tra session if (user.current_session_id !== decoded.sessionId) { return res.status(401).json({ success: false, message: 'Phiên đăng nhập đã hết hạn', }); } // Gắn thông tin user vào request req.user = { userId: user.id, username: user.username, email: user.email, role: decoded.role, sessionId: decoded.sessionId, }; next(); } catch (error) { if (error.name === 'TokenExpiredError') { return res.status(401).json({ success: false, message: 'Token đã hết hạn', }); } if (error.name === 'JsonWebTokenError') { return res.status(401).json({ success: false, message: 'Token không hợp lệ', }); } console.error('Auth middleware error:', error); return res.status(500).json({ success: false, message: 'Lỗi xác thực', error: error.message, }); } }; /** * Middleware kiểm tra role */ const requireRole = (allowedRoles) => { return (req, res, next) => { if (!req.user) { return res.status(401).json({ success: false, message: 'Chưa xác thực', }); } const userRole = req.user.role; if (!allowedRoles.includes(userRole)) { return res.status(403).json({ success: false, message: 'Không có quyền truy cập', required_role: allowedRoles, your_role: userRole, }); } next(); }; }; /** * Middleware kiểm tra permission cụ thể */ const requirePermission = (permission) => { return async (req, res, next) => { if (!req.user) { return res.status(401).json({ success: false, message: 'Chưa xác thực', }); } try { const user = await UsersAuth.findByPk(req.user.userId, { include: [{ model: Role, as: 'role', include: [{ model: Permission, as: 'permissions', }], }], }); if (!user) { return res.status(401).json({ success: false, message: 'User không tồn tại', }); } // Kiểm tra user có permission này không const hasPermission = user.role?.permissions?.some( p => p.permission_code === permission ); if (!hasPermission) { return res.status(403).json({ success: false, message: 'Không có quyền thực hiện hành động này', required_permission: permission, }); } next(); } catch (error) { console.error('Permission check error:', error); return res.status(500).json({ success: false, message: 'Lỗi kiểm tra quyền', error: error.message, }); } }; }; /** * Middleware xác thực optional - không bắt buộc phải có token */ const optionalAuth = async (req, res, next) => { try { const authHeader = req.headers.authorization; const token = authHeader && authHeader.replace('Bearer ', ''); if (!token) { // Không có token, tiếp tục nhưng không có req.user req.user = null; return next(); } // Có token, thử verify const decoded = jwt.verify(token, JWT_SECRET); const user = await UsersAuth.findByPk(decoded.userId); if (user && user.is_active && user.current_session_id === decoded.sessionId) { req.user = { userId: user.id, username: user.username, email: user.email, role: decoded.role, sessionId: decoded.sessionId, }; } else { req.user = null; } next(); } catch (error) { // Token không hợp lệ, tiếp tục nhưng không có req.user req.user = null; next(); } }; module.exports = { authenticateToken, requireRole, requirePermission, optionalAuth, };