Nestjs 튜토리얼 따라하기 8편
15 Aug 2021 | BackendNestjs 튜토리얼 따라하기 8편
Guards
-
Guard는 @Injectable() 데코레이터를 사용하는 클래스이며
CanActivate
인터페이스를 구현하여 정의 된다. -
Guard는 권한부여에 대한 결과를 처리한다. 이는 일반적으로 express의 미들웨어에 의해 처리 되었다.
express의 미들웨어는 next()를 호출하게 되면 그 이후에 무슨 함수가 호출될 지 모르지만 Guards는 ExecutionContext
에 접근할 수 있으므로 다음에 실행될 항목을 정확하게 알 수 있다.
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);
}
}
Execution context
```canActive() 함수는 파라미터로
ExecutionContext 를 갖는다.
ExecutionContext는
ArgumentHost`로 부터 상속된다.
Role-based authentication
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
@Injectable()
export class RolesGuard implements CanActivate {
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
return true;
}
}
Guard 적용하기
Pipe처럼 Guard도 Controller에 적용하거나, 전역으로 적용할 수 있다. Controller에 적용하기 위해서 @UseGuards()
데코레이터를 사용해야 한다.
@Controller('cats')
@UseGuards(RolesGuard)
export class CatsController {}
전역으로 적용하기 위해서 useGlobalGuards()
메소드를 사용한다.
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new RolesGuard());
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
@Module({
providers: [
{
provide: APP_GUARD,
useClass: RolesGuard,
},
],
})
export class AppModule {}
Setting roles per handler
위에서 구현한 RolesGuard
가 잘 작동하기 위해서 각 Controller Route마다 어떤 권한을 가지고 있을 때 권한을 허가할건지 설정해야한다.
@Post()
@SetMetadata('roles', ['admin'])
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
혹은 직접 데코레이터를 생성해서 권한을 설정할 수 있다.
import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
@Post()
@Roles('admin')
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto);
}
위에서 구현한 것을 모두 합치면
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;
return matchRoles(roles, user.roles);
}
}