NestJs - Guard

choko's avatar
Jun 29, 2024
NestJs - Guard
 
  • 애플리케이션을 보호하는 역할 담당
    • Nest에서의 요청은 컨트롤러에 도달하기 전에, 반드시 가드를 거쳐가도록 되어 있다.
    • @Injectable() 데코레이터가 있어야 하고, CanActivate 인터페이스를 반드시 implement 해야 한다.
    • 특정 상황들에 따라, request가 route handler에 의해 handle될 지 말지를 결정한다.
      • 미들웨어와 유사한 역할 수행
    • Guard는 모든 미들웨어의 다음에 수행되고, interceptor나 pipe 이전에 실행된다.
    •  

Authorization guard

 
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 validateRequest(request); } }
 
  • Guard도 Pipe나 Exception Filter처럼 다양한 scope 범위를 가진다.
    • // class 범위 @Controller('cats') @UseGuards(RolesGuard) export class CatsController {} // global import { Module } from '@nestjs/common'; import { APP_GUARD } from '@nestjs/core'; @Module({ providers: [ { provide: APP_GUARD, useClass: RolesGuard, }, ], }) export class AppModule {}
curl -X POST http://localhost:3000/auth/login -d '{"username": "john", "password": "changeme"}' -H "Content-Type: application/json {"access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}

Guard example

  • @SetMetadata()
    • Router handler에게 metadata를 붙일 수 있다. 이 metadata로, guard가 결정을 내리기 위해 필요한 role data를 부여해준다.
    • //roles.decorator.ts import { SetMetadata } from '@nestjs/common'; export const Roles = (...roles: string[]) => SetMetadata('roles', roles); //cats.controller.ts @Post() @Roles('admin') async create(@Body() createCatDto: CreateCatDto) { this.catsService.create(createCatDto); }
 
  • 위의 메타데이터를 이용하여, admin role만 허락하는 Guard
    • //roles.guard.ts import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const roles = this.reflector.get<string[]>('roles', context.getHandler()); if (!roles) { return true; } const request = context.switchToHttp().getRequest(); const user = request.user; // -> node.js 생태계에서 request.user에 user object를 붙이는게 통상적이다. return matchRoles(roles, user.roles); } }
Share article

Tom의 TIL 정리방