Ответ
В моих проектах на 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') по умолчанию имеет доступ ко всем эндпоинтам. - Для сложных политик доступа (например, «менеджер может редактировать только своих подчиненных») внутри контроллера добавляется дополнительная бизнес-логика.
Ответ 18+ 🔞
А, ну это ж классика, ебать мои старые костыли! Каждый второй проект на Node.js через это проходит. Слушай, как я обычно эту карусель кручу.
В общем, берёшь JWT – это как пропуск в закрытый клуб, только вместо штампа – куча непонятных букв и цифр. И 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'
}
});
Всё просто: почта, хеш пароля (никогда, слышишь, НИКОГДА пароль в открытую не пили!) и роль. Роли – как в театре: 'user' (зритель), 'manager' (осветитель) и 'admin' (режиссёр, которому всё можно).
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 };
authenticate – это как охранник на входе: "Предъяви пропуск!" Нет токена или он кривой – иди нахуй, 401 ошибка. authorize – уже второй охранник внутри: "А тебе в этот кабинет можно?" Проверяет роль. Не в списке – получи 403, свободен.
3. Ну и как это всё прикрутить к роутам:
// 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-токен при логине зашивается.
authenticateпроверяет, не хуй в пальто ли этот токен, и если всё ок – вешает данные наreq.user.authorizeсмотрит: а твоя роль в списке приглашённых? Админ ('admin') – по умолчанию царь и бог, ему везде зелёный свет.- Если логика сложнее (типа "менеджер может только своих подопечных трогать") – это уже внутри самого контроллера дописываешь, обычными
if-ами. Middleware – только дверь открывает, а что внутри делать – твои проблемы.
Вот и вся магия. Ничего космического, но работает как швейцарские часы, если, конечно, секретный ключ (JWT_SECRET) не закоммитишь в публичный репозиторий, а то будет тебе хиросима и нигерсраки на ровном месте.