Ответ
Плюсы JWT в Node.js:
- Stateless (без состояния): Серверу не нужно хранить сессию в памяти или БД. Это упрощает архитектуру и горизонтальное масштабирование: любой инстанс приложения может проверить токен.
- Самодостаточность: В payload токена можно хранить базовые данные о пользователе (userId, роль), уменьшая количество запросов к БД.
- Безопасность подписи: Использование алгоритмов вроде HS256 или RS256 гарантирует, что токен не был изменен после выдачи.
- Универсальность: Легко использовать между различными доменами (CORS) и типами клиентов (веб, мобильные приложения, микросервисы).
Минусы и риски JWT:
- Немедленный отзыв невозможен: Токен валиден до истечения срока (exp). Для решения используют короткоживущие access-токены (минуты) и долгоживущие refresh-токены, которые можно отозвать на сервере.
- Размер: Токен больше, чем session ID, и передается с каждым запросом, что увеличивает трафик.
- Уязвимость к XSS при неправильном хранении: Если хранить JWT в
localStorage, он доступен для скриптов. Более безопасный способ — использоватьhttpOnlyкуки (хотя это усложняет работу с мобильными приложениями). - Данные устаревают: Информация в payload может не соответствовать актуальным данным в БД (например, если роль пользователя изменилась).
Пример реализации с библиотекой jsonwebtoken:
// Генерация токена
const jwt = require('jsonwebtoken');
const accessToken = jwt.sign(
{ userId: 123, role: 'user' }, // payload
process.env.JWT_SECRET, // секретный ключ
{ expiresIn: '15m' } // срок жизни
);
const refreshToken = jwt.sign(
{ userId: 123 },
process.env.JWT_REFRESH_SECRET,
{ expiresIn: '7d' }
);
// Middleware для проверки токена в Express
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer <token>
if (!token) return res.sendStatus(401);
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.sendStatus(403); // Невалидный или просроченный токен
req.user = user; // Добавляем данные пользователя в объект запроса
next();
});
}
app.get('/protected', authenticateToken, (req, res) => {
res.json({ message: `Hello user ${req.user.userId}` });
});