Skip to main content
Практика завдань

Що таке guards у NestJS і як реалізувати аутентифікацію?

Guards у NestJS

Guards визначають, чи слід обробляти запит обробником маршруту чи ні. Вони реалізують інтерфейс CanActivate і повертають true (дозволити) або false (відмовити). Guards найчастіше використовуються для автентифікації та авторизації.


Створення Guard

typescript
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Observable } from 'rxjs'; @Injectable() export class AuthGuard implements CanActivate { canActivate( context: ExecutionContext, ): boolean | Promise<boolean> | Observable<boolean> { const request = context.switchToHttp().getRequest(); return this.validateRequest(request); } private validateRequest(request: any): boolean { return !!request.headers.authorization; } }

JWT Auth Guard

typescript
// guards/jwt-auth.guard.ts import { Injectable, CanActivate, ExecutionContext, UnauthorizedException } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import { Request } from 'express'; @Injectable() export class JwtAuthGuard implements CanActivate { constructor(private jwtService: JwtService) {} async canActivate(context: ExecutionContext): Promise<boolean> { const request = context.switchToHttp().getRequest<Request>(); const token = this.extractToken(request); if (!token) throw new UnauthorizedException('Токен не надано'); try { const payload = await this.jwtService.verifyAsync(token, { secret: process.env.JWT_SECRET, }); request['user'] = payload; // прикріпити до запиту return true; } catch { throw new UnauthorizedException('Недійсний або прострочений токен'); } } private extractToken(request: Request): string | null { const [type, token] = request.headers.authorization?.split(' ') ?? []; return type === 'Bearer' ? token : null; } }

Roles Guard (Авторизація)

typescript
// guards/roles.guard.ts import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { ROLES_KEY } from '../decorators/roles.decorator'; @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const requiredRoles = this.reflector.getAllAndOverride<string[]>( ROLES_KEY, [context.getHandler(), context.getClass()], ); if (!requiredRoles) return true; // ролі не потрібні → дозволити const { user } = context.switchToHttp().getRequest(); return requiredRoles.some(role => user.roles?.includes(role)); } } // decorators/roles.decorator.ts import { SetMetadata } from '@nestjs/common'; export const ROLES_KEY = 'roles'; export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);

Застосування Guards

typescript
// Рівень методу @Get('profile') @UseGuards(JwtAuthGuard) getProfile(@Request() req) { return req.user; } // Рівень контролера @Controller('admin') @UseGuards(JwtAuthGuard, RolesGuard) export class AdminController {} // Глобально (всі маршрути) // main.ts app.useGlobalGuards(new JwtAuthGuard(jwtService)); // Або через модуль (бажано — підтримує DI) @Module({ providers: [ { provide: APP_GUARD, useClass: JwtAuthGuard }, ], })

Декоратор публічних маршрутів

typescript
// decorators/public.decorator.ts export const IS_PUBLIC_KEY = 'isPublic'; export const Public = () => SetMetadata(IS_PUBLIC_KEY, true); // У JwtAuthGuard.canActivate(): const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) return true; // пропустити автентифікацію для маршрутів @Public() // Використання: @Public() @Post('auth/login') login(@Body() loginDto: LoginDto) { ... }

Guard vs Middleware vs Interceptor

GuardMiddlewareInterceptor
Має ExecutionContext
Може отримувати метадані
ПризначенняАвтентифікація / АвторизаціяЛогування, CORSПеретворення відповіді
Може перервати запит

Резюме

Guards є шаром безпеки NestJS. Реалізуйте CanActivate, отримуйте запит через ExecutionContext і повертайте true або викидайте UnauthorizedException. Використовуйте Reflector + кастомні метадані декоратори (як-от @Roles()) для детального контролю доступу на основі ролей.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?
Практика завдань