Ответ
В моих проектах на Node.js я обычно строю такую систему на основе JWT (JSON Web Tokens) для аутентификации и middleware для авторизации по ролям. Вот примерный стек и реализация:
1. Структура данных (на примере Mongoose):
const userSchema = new mongoose.Schema({
email: { type: String, unique: true, required: true },
passwordHash: { type: String, required: true },
role: {
type: String,
enum: ['user', 'manager', 'admin'],
default: 'user'
}
});
2. Middleware для проверки аутентификации и роли:
// authMiddleware.js
const jwt = require('jsonwebtoken');
const authenticate = (req, res, next) => {
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) return res.status(401).json({ error: 'Access denied' });
try {
const verified = jwt.verify(token, process.env.JWT_SECRET);
req.user = verified; // В токене содержится { userId, role }
next();
} catch (err) {
res.status(400).json({ error: 'Invalid token' });
}
};
const authorize = (...allowedRoles) => {
return (req, res, next) => {
if (!req.user || !allowedRoles.includes(req.user.role)) {
return res.status(403).json({ error: 'Forbidden: insufficient privileges' });
}
next();
};
};
module.exports = { authenticate, authorize };
3. Применение в роутах Express:
// routes/admin.js
const { authenticate, authorize } = require('../middleware/authMiddleware');
const router = require('express').Router();
// Только админ
router.get('/stats', authenticate, authorize('admin'), getStats);
// Админ и менеджер
router.put('/users/:id', authenticate, authorize('admin', 'manager'), updateUser);
// Любой аутентифицированный пользователь
router.get('/profile', authenticate, (req, res) => {
res.json(req.user);
});
Ключевые моменты:
- Роль пользователя хранится в БД и включается в JWT-токен при логине.
- Middleware
authenticateпроверяет валидность токена и добавляет данные пользователя вreq.user. - Middleware
authorizeпроверяет, есть ли у пользователя одна из разрешенных ролей. Админ ('admin') по умолчанию имеет доступ ко всем эндпоинтам. - Для сложных политик доступа (например, «менеджер может редактировать только своих подчиненных») внутри контроллера добавляется дополнительная бизнес-логика.