@Injectable() 데코레이터가 달린 클래스
CanActivate 인터페이스를 구현
단일 책임 원칙
인증
인증/권한은 전통적인 Express 애플리케이션에서 종종 미들웨어에 의해 처리
request 객체에 속성을 첨부하는 작업은 특정 라우트 컨텍스트(및 메타데이터)와 강하게 연결되지 않기 때문next() 함수 호출 후에 실행될지 알 수 없음ExecutionContext 인스턴스에 접근하여 이후 실행 대상 확인 가능예외 필터, 파이프, 인터셉터와 마찬가지로 요청/응답 사이클의 정확한 지점에서 처리 로직을 삽입하도록 설계, 선언적으로 수행 가능
가드는 모든 미들웨어가 실행된 후, 인터셉터나 파이프가 실행되기 전에 실행
충분한 권한을 가지고 있을 때만 사용하는 경우
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() 함수를 구현해야 함
현재 요청이 허용되는지 여부를 나타내는 boolean 값 반환
이는 동기적으로 또는 비동기적으로(Promise 또는 Observable을 통해) 응답 반환
true를 반환하면 요청이 처리false를 반환하면 Nest는 요청을 거부canActivate() 함수는 단일 인수로 ExecutionContext 인스턴스 받음ExecutionContext는 ArgumentsHost를 상속
ArgumentsHost를 확장해 ExecutionContext는 현재 실행 프로세스에 대한 추가 세부 정보를 제공하는 여러 새로운 헬퍼 메서드를 추가
모든 역할 허용에서 특정 역할 허용 예시:
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;
}
}
컨트롤러 범위, 메서드 범위 또는 전역 범위로 설정 가능
@UseGuards() 데코레이터를 사용하여 컨트롤러 범위 가드를 설정@Controller('cats')
@UseGuards(RolesGuard)
export class CatsController {}
인스턴스가 아닌 클래스로 전달하여 프레임워크가 인스턴스화를 책임지도록 하고 의존성 주입을 활성화:
@Controller('cats')
@UseGuards(new RolesGuard())
export class CatsController {}
단일 메서드에 적용시 메서드 수준에서 @UseGuards() 데코레이터를 적용
전역 가드는 Nest 애플리케이션 인스턴스의 useGlobalGuards() 메서드를 사용:
const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new RolesGuard());
의존성 주입 측면에서 전역 가드는 모듈 외부에서 등록될 경우(위 예제에서처럼 useGlobalGuards()를 사용하여) 의존성을 주입할 수 없음
모듈 내부에서 직접 전역 가드를 설정:
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
@Module({
providers: [
{
provide: APP_GUARD,
useClass: RolesGuard,
},
],
})
export class AppModule {}
역할이나 각 핸들러에 대해 허용되는 역할에 대해 알지 못하는 단순한 상태
커스텀 메타데이터로 해결
Reflector.createDecorator 정적 메서드,
생성된 데코레이터나 내장된 @SetMetadata() 데코레이터를 통해,
라우트 핸들러에 커스텀 메타데이터를 첨부 가능
Reflector는 프레임워크에 의해 제공되며 @nestjs/core 패키지import { Reflector } from '@nestjs/core';
export const Roles = Reflector.createDecorator<string[]>();
Roles 데코레이터는 string[] 타입의 단일 인수를 받는 함수이제 이 데코레이터를 사용하려면 핸들러에 주석을 추가하기만 하면 됩니다:
@Post()
@Roles(['admin'])
async create(@Body() createCatDto: CreateCatDto) {
this.catsService.create(createCatDto
);
}
Reflector.createDecorator메서드를 사용하는 대신 내장된@SetMetadata()데코레이터를 사용할 수 있습니다. 자세한 내용은 여기를 참조하세요.
현재 처리 중인 라우트의 실제 역할과 현재 사용자에게 할당된 역할을 비교하여 조건부 처리:
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Roles } from './roles.decorator';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const roles = this.reflector.get(Roles, context.getHandler());
if (!roles) {
return true;
}
const request = context.switchToHttp().getRequest();
const user = request.user;
return matchRoles(roles, user.roles);
}
}
Reflection and metadata 섹션에서
Reflector를 컨텍스트에 맞게 사용하는 방법에 대해 자세히 알아보세요.
권한이 부족한 경우라면:
{
"statusCode": 403,
"message": "Forbidden resource",
"error": "Forbidden"
}
false를 반환하면 프레임워크는 ForbiddenException 을 기본 반환특정 예외:
throw new UnauthorizedException();
가드에서 발생한 모든 예외는 예외 레이어에 의해 처리
실제 예제에 대해 자세히 알아보려면 여기를 참조하세요.