При работе с аутентификацией в Node.js часто используется подход, при
котором клиент передаёт токен в каждом запросе, а сервер извлекает из
него данные пользователя и закрепляет их в объекте запроса. Это
позволяет дальше по цепочке middleware и обработчиков обращаться к
req.user без повторного разбора токена.
В экосистеме JavaScript для задач шифрования и защиты данных в
токенах нередко используется библиотека Iron из пакета
@hapi/iron. Она обеспечивает безопасное «упаковывание» и
«распаковку» данных с использованием симметричного шифрования.
req.user в архитектуре приложенияОбъект req.user является стандартным способом хранения
информации о текущем аутентифицированном пользователе в большинстве
HTTP-фреймворков (Express, Koa через адаптеры и т.д.).
Типичное содержимое:
После успешной аутентификации вся эта информация должна быть доступна на уровне запроса без повторного обращения к базе данных.
Библиотека Iron реализует механизм защищённой сериализации данных:
При обратной операции происходит полная проверка целостности и расшифровка.
Поток обработки обычно выглядит следующим образом:
Authorizationreq.userreq.userimport Iron from '@hapi/iron';
const PASSWORD = process.env.IRON_PASSWORD;
export async function authMiddleware(req, res, next) {
try {
const header = req.headers.authorization;
if (!header || !header.startsWith('Bearer ')) {
req.user = null;
return next();
}
const token = header.slice(7);
const session = await Iron.unseal(
token,
PASSWORD,
Iron.defaults
);
req.user = session.user;
next();
} catch (err) {
req.user = null;
next();
}
}
При создании токена обычно используется обёртка над пользовательскими данными:
const session = {
user: {
id: 42,
email: 'user@example.com',
role: 'admin'
},
createdAt: Date.now()
};
Далее этот объект «запечатывается»:
const sealed = await Iron.seal(
session,
PASSWORD,
Iron.defaults
);
Полученная строка и передаётся клиенту.
req.user как центральной точки доступаПосле прохождения middleware объект запроса получает структуру:
req.user = {
id: 42,
email: 'user@example.com',
role: 'admin'
};
Дальнейшая логика приложения опирается исключительно на этот объект:
import express from 'express';
import { authMiddleware } from './authMiddleware.js';
const app = express();
app.use(authMiddleware);
app.get('/profile', (req, res) => {
if (!req.user) {
return res.status(401).json({ error: 'Unauthorized' });
}
res.json({
profile: req.user
});
});
Типичная архитектура включает несколько слоёв:
Отвечает только за получение строки из заголовка.
Преобразует токен в объект данных.
Проверяет права доступа на основе req.user.
Ошибки могут возникать по причинам:
Стандартная стратегия обработки — сброс пользователя:
catch (err) {
req.user = null;
}
и передача управления дальше.
Хотя JWT является более распространённым стандартом, Iron выполняет схожую задачу, но с отличиями:
В результате req.user формируется только после полной
расшифровки.
req.userНе рекомендуется помещать в req.user:
Оптимальный подход — минимальный набор идентификаторов и ролей, остальное извлекается при необходимости.
req.user в сервисном слоеПосле формирования объекта он может передаваться дальше:
function getDashboardData(req) {
const userId = req.user.id;
return database.findDashboardByUserId(userId);
}
Это позволяет полностью исключить повторную дешифровку токена на уровне бизнес-логики.
При высоконагруженных системах допустимо кэширование результата Iron-дешифровки в рамках одного запроса:
req.userПри работе с req.user важно фиксировать структуру:
/**
* @typedef {Object} User
* @property {number} id
* @property {string} email
* @property {string} role
*/
/** @type {User|null} */
req.user;
Это снижает вероятность ошибок при доступе к полям.
Иногда в токен помещается расширенный контекст:
const session = {
user: {
id: 42,
email: 'user@example.com'
},
permissions: ['read', 'write'],
deviceId: 'abc123'
};
После распаковки middleware может нормализовать структуру:
req.user = session.user;
req.permissions = session.permissions;
Параметры Iron.defaults задают:
Изменение этих параметров требует строгого согласования между клиентом и сервером, иначе расшифровка станет невозможной.
Чистая архитектура предполагает, что:
req.userТакой подход снижает связанность компонентов и упрощает тестирование.