- 애플리케이션을 보호하는 역할 담당
- 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);
}
}
canActivate()
ExecutionContext
를 argument로 가진다. 이 값으로, 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