Гид по технологиям

Аутентификация и безопасность REST API в Nest.js с JWT и MongoDB

7 min read Веб-разработка Обновлено 15 Dec 2025
Nest.js JWT + MongoDB: руководство по аутентификации
Nest.js JWT + MongoDB: руководство по аутентификации

Скриншот редактора кода с JavaScript на фоне и логотипом Nest.js на переднем плане.

Nest.js — это каркас (framework) поверх Node.js и Express.js, который предоставляет структурированную архитектуру, модульность и упрощённые абстракции. Express даёт свободу и лёгкость, но не диктует структуру — Nest.js устраняет разрыв, предлагая шаблон проектирования, который облегчает поддержку и масштабирование API.

Что вы получите из этого руководства

  • Готовый шаблон проекта Nest.js с подключённой MongoDB через Mongoose.
  • Реализацию регистрации пользователей с хешированием пароля (bcrypt).
  • Вход (login) с выдачей JWT и защитой маршрутов через Guard.
  • Плейбук по безопасности: хранение секретов, расширение авторизации, рекомендации по тестированию.

Важно: в примерах используется JSON Web Token (JWT) для аутентификации. JWT удобен и распространён, но требует внимательного управления сроками жизни, секретами и политиками отзыва/обновления токенов.

Содержание

  • Настройка проекта Nest.js
  • Подключение MongoDB (Mongoose)
  • Модель пользователя и сервис аутентификации
  • Guard для проверки JWT
  • Контроллер API и модули
  • Практики безопасности и hardening
  • Альтернативные подходы и когда JWT не подходит
  • Чек-листы и тестовые сценарии
  • Краткое резюме

Требования и предварительная подготовка

  • Node.js (рекомендуется LTS) и npm.
  • Локальная или облачная MongoDB (atlas или другая).
  • Установленный Nest CLI (опционально, можно создавать файлы вручную).

Настройка проекта Nest.js

Установите Nest CLI глобально и создайте проект:

npm i -g @nestjs/cli
nest new nest-jwt-api

Выберите npm как пакетный менеджер, дождитесь установки зависимостей, затем перейдите в каталог проекта и запустите его:

cd nest-jwt-api
npm run start

Установите дополнительные зависимости, которые потребуются в проекте:

npm install mongodb mongoose @nestjs/mongoose @types/bcrypt bcrypt jsonwebtoken @nestjs/jwt

Примечание: пакет @types/bcrypt нужен только для TypeScript-типов при использовании нативного bcrypt; альтернативно можно использовать bcryptjs.

Терминал Nest.js CLI со списком пакетных менеджеров.

Подключение MongoDB

Создайте базу данных (локально или в облаке) и получите строку подключения (URI). Создайте файл .env в корне проекта и поместите туда:

MONGO_URI="connection string"

Откройте src/app.module.ts и добавьте подключение Mongoose и ConfigModule:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserAuthModule } from './user-auth/user-auth.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      envFilePath: '.env',
      isGlobal: true,
    }),
    MongooseModule.forRoot(process.env.MONGO_URI),
    UserAuthModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Модуль ConfigModule сделает переменные окружения доступными по всему приложению, а MongooseModule установит соединение с MongoDB.

Создание модуля аутентификации пользователя

Для структурирования кода создайте модуль user-auth через CLI (или вручную):

nest g module user-auth

CLI автоматически добавит модуль в app.module.ts. Далее создадим схему пользователя.

Схема пользователя (Mongoose)

Создайте файл src/user-auth/schemas/user-auth.schema.ts со следующим кодом:

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema({ timestamps: true })
export class User {
  @Prop()
  username: string;

  @Prop()
  password: string;
}

export type UserDocument = User & Document;
export const UserSchema = SchemaFactory.createForClass(User);

Эта схема хранит username и захешированный password. Поле timestamps добавляет createdAt и updatedAt автоматически.

Сервис аутентификации пользователей

Сгенерируйте сервис:

nest g service user-auth

Откройте src/user-auth/user-auth.service.ts и добавьте логику регистрации, входа и получения пользователей:

import { Injectable, NotFoundException, Logger, UnauthorizedException } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User } from './schemas/user-auth.schema';
import * as bcrypt from 'bcrypt';
import { JwtService } from '@nestjs/jwt';

@Injectable()
export class UserAuthService {
  private readonly logger = new Logger(UserAuthService.name);
  constructor(@InjectModel(User.name) private userModel: Model, private jwtService: JwtService) {}

  async registerUser(username: string, password: string): Promise<{ message: string }> {
    try {
      const hash = await bcrypt.hash(password, 10);
      await this.userModel.create({ username, password: hash });
      return { message: 'User registered successfully' };
    } catch (error) {
      throw new Error('An error occurred while registering the user');
    }
  }

  async loginUser(username: string, password: string): Promise {
    try {
      const user = await this.userModel.findOne({ username });
      if (!user) {
        throw new NotFoundException('User not found');
      }
      const passwordMatch = await bcrypt.compare(password, user.password);
      if (!passwordMatch) {
        throw new UnauthorizedException('Invalid login credentials');
      }
      const payload = { userId: user._id };
      const token = this.jwtService.sign(payload);
      return token;
    } catch (error) {
      console.log(error);
      throw new UnauthorizedException('An error occurred while logging in');
    }
  }

  async getUsers(): Promise {
    try {
      const users = await this.userModel.find({});
      return users;
    } catch (error) {
      this.logger.error(`An error occurred while retrieving users: ${error.message}`);
      throw new Error('An error occurred while retrieving users');
    }
  }
}

Ключевые моменты:

  • Пароли хешируются с saltRounds = 10.
  • JWT создаётся через JwtService.
  • Возвращается строка токена при логине.

Guard для проверки JWT

Чтобы защитить маршруты, создайте Guard, который извлекает токен из заголовка Authorization и верифицирует его.

Создайте src/user-auth/auth.guard.ts:

import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { secretKey } from './config';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private jwtService: JwtService) {}

  async canActivate(context: ExecutionContext): Promise {
    const request = context.switchToHttp().getRequest();
    const token = this.extractTokenFromHeader(request);
    if (!token) {
      throw new UnauthorizedException();
    }
    try {
      const payload = await this.jwtService.verifyAsync(token, {
        secret: secretKey.secret,
      });
      request['user'] = payload;
    } catch {
      throw new UnauthorizedException();
    }
    return true;
  }

  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}

Создайте также конфигурацию секрета в src/user-auth/config.ts:

export const secretKey = {
  secret: 'SECTRET VALUE.',
};

Важно: никогда не храните секрет напрямую в коде в продакшене. Используйте переменные окружения, секреты провайдера, Vault или другие безопасные хранилища.

Контроллер API

Сгенерируйте контроллер:

nest g controller user-auth

В контроллере реализуйте маршруты регистрации, логина и получения списка пользователей. Примените UseGuards(AuthGuard) к маршруту получения пользователей, чтобы ограничить доступ только авторизованным.

(Код контроллера можно взять из репозитория проекта; здесь важно привязать сервис и Guard внутри модуля.)

Обновление user-auth.module.ts

Файл src/user-auth/user-auth.module.ts должен подключать MongooseFeature и JwtModule:

import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { UserAuthController } from './user-auth.controller';
import { UserAuthService } from './user-auth.service';
import { MongooseModule } from '@nestjs/mongoose';
import { UserSchema } from './schemas/user-auth.schema';
import { secretKey } from './config';

@Module({
  imports: [
    MongooseModule.forFeature([{ name: 'User', schema: UserSchema }]),
    JwtModule.register({
      secret: secretKey.secret,
      signOptions: { expiresIn: '1h' },
    }),
  ],
  controllers: [UserAuthController],
  providers: [UserAuthService],
})
export class UserAuthModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {}
}

После этого запустите сервер и протестируйте маршруты через Postman или curl:

npm run start

Практики безопасности и hardening

Важно рассматривать безопасность на нескольких уровнях:

  • Хранение секретов: используйте переменные окружения, менеджер секретов (HashiCorp Vault, AWS Secrets Manager).
  • Срок жизни токенов: короткий access token (например, 15–60 минут) + refresh token с более длительным сроком жизни.
  • Отзыв токенов: хранение blacklist/revocation list или использование версий/идентификаторов в базе.
  • HTTPS: все клиент-сервер соединения должны быть через TLS.
  • Ограничение попыток входа: rate limiting, блокировка по IP или аккаунту.
  • Валидация входных данных: Joi или class-validator для DTO.
  • CSP, CORS и заголовки безопасности: helmet, настройка CORS по необходимости.
  • Логирование и мониторинг: следите за подозрительными попытками входа.

Важно: JWT — это утверждение о подлинности. Сам по себе JWT не даёт полной защиты от компрометации учётных записей или токенов.

Альтернативные подходы и когда JWT не подходит

  • Сессионная аутентификация (server-side sessions) лучше подходит, если нужен мгновенный отзыв сессии и минимальная сложность реализации.
  • OAuth2 / OpenID Connect — когда требуется сторонняя авторизация, делегирование или единая точка входа (SSO).
  • Mutual TLS — для машин-к-машине аутентификации в высокозащищённых средах.

Когда JWT может не подходить:

  • Нужно мгновенно отзывать доступ большого количества пользователей без дополнительного хранилища.
  • Требуется крайне строгий контроль сессий на сервере и высокая чувствительность к компрометации токенов.

Ментальные модели и эвристики

  • Модель доверия: JWT = кратковременное доверие. Не храните в токене чувствительную информацию.
  • Разделение ролей: аутентификация (кто вы) и авторизация (что вы можете делать).
  • Defense in Depth: используйте несколько слоёв защиты — валидация, шифрование, лимитирование, аудит.

Чек-лист перед развертыванием

  • Секреты вынесены из кода в безопасное хранилище.
  • HTTPS настроен для всех входящих соединений.
  • CORS ограничен нужными доменами.
  • Логи настроены, нет утечек паролей в логах.
  • Пароли хранятся в виде хешей с подходящим rounds.
  • Тесты на основные сценарии: регистрация, логин, доступ защищённых маршрутов.
  • Политики восстановления/сброса пароля реализованы.

Тестовые сценарии и критерии приёмки

Критерии приёмки (минимум):

  • Регистрация возвращает 200 и сообщение успеха при валидных данных.
  • Логин возвращает валидный JWT при корректных учётных данных.
  • Доступ к /users без токена возвращает 401.
  • Доступ к /users с корректным токеном возвращает список пользователей.

Тест-кейсы (примеры):

  • Попытка регистрации с уже существующим username.
  • Логин с неверным паролем — должен вернуть 401.
  • Использование просроченного токена — должен вернуть 401.

Мини-методология для доработки в продакшн

  1. Провести аудит зависимостей и обновить пакеты до LTS-версий.
  2. Перенести секреты в безопасное хранилище.
  3. Добавить refresh-token механизм с хранением в базе.
  4. Настроить rate-limiter (например, express-rate-limit/redis).
  5. Написать интеграционные тесты и CI-пайплайн.

Примеры конфигураций и сниппеты

  • Рекомендация по expiration: access token 15–60 минут, refresh token 7–30 дней.
  • bcrypt saltRounds: 10–12 для балансa между безопасностью и производительностью.

Примеры отказов и крайние случаи

  • Если секрет JWT случайно утёк — следует сменить secret и реализовать отозванные токены (черный список) или поддерживать версию ключа в payload.
  • Если база пользователей удалена — резервные копии и политика восстановления крайне важны.

Приватность и соответствие требованиям (GDPR)

  • Сохраняйте минимально необходимые персональные данные.
  • У пользователей должно быть право запроса удаления их данных (Right to be forgotten).
  • Логи и бэкапы не должны содержать необработанные пароли.

Важно: юридические требования зависят от юрисдикции — проконсультируйтесь с юридическим отделом для соответствия GDPR/локальным законам.

Резюме

Этот материал показал, как быстро начать с Nest.js и MongoDB, реализовать базовую регистрацию/логин с JWT и защитой маршрутов через Guard. Но сама базовая реализация — только начало: для безопасного продакшна необходимы дополнительные меры — управление секретами, политика обновления токенов, мониторинг и тестирование.

Важно: JWT удобен, но не заменяет комплексной политики безопасности. Проверяйте архитектуру и применяйте defense-in-depth.

Ключевые шаги далее: вынести секреты, добавить refresh token, настроить rate limiting, покрыть тестами и сделать аудит безопасности.

FAQ

Вопрос: Нужно ли использовать refresh токены?

Да. Refresh токены позволяют выдавать короткоживущие access токены и уменьшить риск, если access токен скомпрометирован.

Вопрос: Где хранить JWT на клиенте?

Для SPA чаще используют HttpOnly cookies (без доступа через JS) для повышения защиты от XSS; LocalStorage проще, но уязвим к XSS.

Вопрос: Как отозвать JWT до истечения срока?

Нужно хранить список отозванных токенов (blacklist) или версионировать ключи/учётные записи и проверять соответствие версии при верификации.


Краткое резюме:

  • Nest.js даёт структуру и модульность, Mongoose упрощает работу с MongoDB.
  • JWT реализуется через JwtModule и Guard для защиты маршрутов.
  • В продакшне критичны управление секретами, refresh-токены, rate-limiting и аудит.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как найти приложения для Android Wear 2.0
Android.

Как найти приложения для Android Wear 2.0

Как размыть фон в Canva: 3 простых способа
Дизайн

Как размыть фон в Canva: 3 простых способа

Установить и протестировать Windows 10 S
Windows

Установить и протестировать Windows 10 S

RRoD на Xbox 360: как устранить и диагностировать
Техподдержка

RRoD на Xbox 360: как устранить и диагностировать

Как проверить версию Ubuntu
Linux

Как проверить версию Ubuntu

Как сделать копию документа Word
Работа с документами

Как сделать копию документа Word