Как реализовать механизм обновления токенов в NestJS?
Введение
Механизм обновления токенов (token refresh) является важной частью систем аутентификации, так как позволяет поддерживать пользовательские сессии без необходимости повторной аутентификации. В данной статье мы рассмотрим, как реализовать автоматическую стратегию обновления токенов в приложении на NestJS.
Основные концепции
- Токен доступа (access token): используется для доступа к защищенным ресурсам и имеет короткое время жизни (например, 15 минут).
- Токен обновления (refresh token): используется для получения нового токена доступа и имеет более длительное время жизни (например, 7 дней).
- Когда токен доступа истекает, клиент отправляет токен обновления на сервер, чтобы получить новый токен доступа.
- Сервер проверяет токен обновления, и если он действителен, возвращает новый токен доступа.
Реализация в NestJS
Установка необходимых зависимостей
Сначала установим необходимые пакеты:
npm install @nestjs/jwt passport-jwt
Создание модуля аутентификации
Создадим модуль аутентификации, который будет содержать логику работы с токенами.
import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { AuthService } from './auth.service';
import { AuthController } from './auth.controller';
@Module({
imports: [
JwtModule.register({
secret: 'your-secure-secret', // Убедитесь, что секрет безопасен
signOptions: { expiresIn: '15m' }, // Время жизни токена доступа
}),
],
providers: [AuthService],
controllers: [AuthController],
})
export class AuthModule {}
AuthService: Логика аутентификации и обновления токена
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) {}
async generateAccessToken(userId: number) {
return this.jwtService.sign({ userId });
}
async generateRefreshToken(userId: number) {
return this.jwtService.sign({ userId }, { expiresIn: '7d' }); // Токен обновления
}
async refreshTokens(userId: number, refreshToken: string) {
const payload = this.jwtService.verify(refreshToken); // Проверяем токен обновления
if (!payload) throw new Error('Invalid refresh token');
// Генерируем новый токен доступа
const accessToken = await this.generateAccessToken(userId);
return { accessToken };
}
}
AuthController: Эндпоинт для обновления токена
import { Controller, Post, Body } from '@nestjs/common';
import { AuthService } from './auth.service';
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Post('refresh')
async refreshTokens(@Body('refreshToken') refreshToken: string) {
// Здесь userId должен быть получен из базы данных, часто в реальных приложениях
const userId = /* logic to get userId from refresh token */;
return this.authService.refreshTokens(userId, refreshToken);
}
}
Клиентская сторона
Для обновления токена с клиентской стороны (например, с использованием fetch):
async function refreshToken() {
const response = await fetch('/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ refreshToken: localStorage.getItem('refreshToken') }),
});
if (response.ok) {
const data = await response.json();
localStorage.setItem('accessToken', data.accessToken);
} else {
// Обработка ошибки: токен обновления недействителен
console.error('Unable to refresh token');
}
}
Заключение
Реализуя механизм обновления токенов в NestJS, вы улучшаете пользовательский опыт, позволяя пользователям оставаться в системе без частой повторной аутентификации. Этот пример служит базовым ориентиром, который можно адаптировать под более сложные сценарии в зависимости от требований вашего приложения.