Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Гарды

Гард (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.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.