@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();
가드에서 발생한 모든 예외는 예외 레이어에 의해 처리
실제 예제에 대해 자세히 알아보려면 여기를 참조하세요.