Гарды
Гард (guard, «охранник») — класс, который решает, можно ли вызвать метод контроллера для этого запроса. Он возвращает true — запрос проходит дальше, false — клиент получает ответ 403. Гарды используют для проверки доступа: вошёл ли пользователь, есть ли у него нужная роль.
Простой гард
Пусть создавать статьи можно только с секретным ключом в заголовке x-api-key. Настоящий вход по паролю появится в пятой главе, а пока хватит ключа.
nest g guard common/guards/api-key --flat// src/common/guards/api-key.guard.ts
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Request } from 'express';
@Injectable()
export class ApiKeyGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest<Request>();
return request.headers['x-api-key'] === 'secret-key';
}
}Метод canActivate() получает ExecutionContext — сведения о текущем запросе. Через него гард достаёт объект запроса Express и читает заголовок.
Подключение к методу
// src/posts/posts.controller.ts
import { Body, Controller, Post, UseGuards } from '@nestjs/common';
import { ApiKeyGuard } from '../common/guards/api-key.guard';
import { CreatePostDto } from './dto/create-post.dto';
import { PostsService } from './posts.service';
@Controller('posts')
export class PostsController {
constructor(private readonly postsService: PostsService) {}
@Post()
@UseGuards(ApiKeyGuard)
create(@Body() dto: CreatePostDto) {
return this.postsService.create(dto);
}
}Отправьте POST-запрос без заголовка — придёт ответ 403 Forbidden resource. С заголовком статья создастся:
curl -X POST http://localhost:3000/posts \
-H "Content-Type: application/json" \
-H "x-api-key: secret-key" \
-d '{"title":"Гарды","content":"Проверка доступа"}'Где ставить гард
| Где | Как | Действует на |
|---|---|---|
| Метод | @UseGuards(ApiKeyGuard) над методом | Один маршрут |
| Контроллер | @UseGuards(ApiKeyGuard) над классом | Все маршруты контроллера |
| Приложение | Провайдер APP_GUARD в модуле | Все маршруты |
Глобальный гард регистрируют в любом модуле:
// src/app.module.ts
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { ApiKeyGuard } from './common/guards/api-key.guard';
@Module({
providers: [{ provide: APP_GUARD, useClass: ApiKeyGuard }],
})
export class AppModule {}Такая запись позволяет гарду получать сервисы через конструктор — это понадобится для входа по токену.
Свой код ошибки
Вместо false гард может бросить исключение. Тогда клиент получит его код и текст:
// src/common/guards/api-key.guard.ts
import { UnauthorizedException } from '@nestjs/common';
if (request.headers['x-api-key'] !== 'secret-key') {
throw new UnauthorizedException('Неверный ключ API');
}
return true;Код 401 означает «вы не представились», а 403 — «вы представились, но доступа нет».
Частая ошибка
Гард выполняется после всех middleware, но до пайпов. Поэтому в гарде ещё нет проверенного DTO: тело запроса там — сырые данные. Не опирайтесь в гарде на поля тела, проверяйте заголовки и пользователя, а данные проверяйте в DTO.