В системах, построенных на основе Iron, механизм аутентификации часто опирается на зашифрованные сессионные токены, содержащие метаданные времени жизни. Основной принцип заключается в том, что каждый токен имеет фиксированное или динамически вычисляемое время истечения, после которого он считается недействительным.
В типичной реализации структура данных токена включает:
При декодировании токена сервер сверяет текущую временную метку с параметром истечения и принимает решение о валидности.
В Iron-конфигурациях срок жизни токена задаётся через параметры шифрования сессии. Чаще всего используется подход, при котором TTL задаётся в миллисекундах или секундах.
Пример логической модели:
const sessionOptions = {
ttl: 1000 * 60 * 15, // 15 минут
encryptionKey: process.env.ENCRYPTION_KEY,
algorithm: 'aes-256-gcm'
};
Ключевое поведение:
Проверка срока действия выполняется в момент каждого запроса, где участвует сессионный токен.
Алгоритм проверки включает несколько этапов:
issuedAt + ttlЛогическая модель проверки:
function isTokenExpired(session) {
const now = Date.now();
return now > session.createdAt + session.ttl;
}
Если условие истинно, токен отклоняется до этапа бизнес-логики приложения.
Тестирование поведения истечения токена требует контролируемого управления временем. В отличие от обычных юнит-тестов, здесь критически важна возможность симуляции временных интервалов.
Используются следующие подходы:
Наиболее распространённый способ тестирования основан на подмене глобального времени выполнения.
Пример с использованием Jest:
jest.useFakeTimers();
test('токен должен истечь', () => {
const token = createSessionToken(user, { ttl: 1000 });
jest.advanceTimersByTime(1500);
const result = validateToken(token);
expect(result).toBe(false);
});
Механика работы:
Альтернативный подход основан на установке минимального времени жизни токена.
const token = createSessionToken(user, {
ttl: 1 // 1 миллисекунда
});
setTimeout(() => {
const isValid = validateToken(token);
console.log(isValid); // ожидается false
}, 10);
Этот метод менее точный, но позволяет проверять реальные асинхронные сценарии.
Отдельный класс тестов связан с проверкой поведения системы при несинхронизированном времени:
Типовой сценарий:
test('должен отклонять токен при значительном сдвиге времени', () => {
const token = createSessionToken(user);
mockSystemTime(Date.now() + 1000 * 60 * 60 * 24);
const result = validateToken(token);
expect(result).toBe(false);
});
Особое внимание уделяется моменту перехода через границу TTL.
Проблемные зоны:
Типовая проверка:
if (now >= expirationTime) {
invalidateSession();
}
Использование >= вместо >
предотвращает неконсистентность состояния.
В системах с несколькими сервисами проверка истечения усложняется из-за рассинхронизации времени.
Используются дополнительные механизмы:
Тестовые сценарии включают имитацию задержек между сервисами и анализ поведения при частично просроченных токенах.
Для диагностики используются логические маркеры:
issuedAtexpiresAtvalidatedAtПример логирования:
console.log({
issuedAt: session.createdAt,
expiresAt: session.createdAt + session.ttl,
validatedAt: Date.now()
});
Это позволяет точно определить момент, в который токен становится недействительным.
После истечения срока токен не должен восстанавливаться даже при повторной валидации без повторной аутентификации.
Типичная ошибка реализации:
Корректная модель всегда выполняет пересчёт времени на каждом запросе, без сохранения результата проверки валидности.