Guards

이준엽·2024년 12월 17일
  1. Guards
    • 인증이나 인가등을 수행한다.
    • express 미들웨어로 구현할 때와 비교하면 excutionContext에 접근 할 수 있다는게 장점
  2. Authorization guard
    • 모든 guard는 canActive() 메소드를 구현해야 한다.
    • monorepo의 adminLevelGuard
      @Injectable()
      export class AdminLevelGuard implements CanActivate {
        constructor(private readonly reflector: Reflector) {}
      
        canActivate(context: ExecutionContext): boolean {
          const allowLevel = this.reflector.get<Partial<AdminLevel>>(
            ALLOW_ADMIN_LEVEL,
            context.getHandler(),
          );
      
          // 관리자 level 제한이 없는 경우
          if (isNil(allowLevel)) {
            return true;
          }
      
          const req = context.switchToHttp().getRequest();
          const admin: Admin = req.user;
      
          // 현재 관리자 레벨이 api 에 허용된 level 보다 크면 403을 throw 한다.
          if (admin.level > allowLevel) {
            throw new ForbiddenException(
              HTTP_RESPONSE_ERROR_CODE.ADMINISTRATOR.ADMINISTRATOR013,
            );
          }
      
          return true;
        }
      }
    • 위의 가드를 이용할 때 context에 접근하는 예시가 나와있다. 이 가드가 적용되는 메소드를 위한 admin Level을 설정해주고 가드에서 context에 접근하여 그 정보를 불러서 지금 현재 유저의 레벨과 비교하여 통과시키고 있다.
    • reflector 클래스를 이용하면 excutionContext에 지정된 key에 대한 메타데이터에 접근할 수 있음
  3. Execution context
    • getHandler()는 호출될 핸들러에 대한 참조를 리턴
      getClass() 메소드는 이 특정 핸들러가 속하는 controller 클래스를 리턴
      ```tsx
      export interface ExecutionContext extends ArgumentsHost {
      	getClass<T = any>(): Type<T>;
      	getHandler(): Function;
      }
      ```
  4. Binding guards
    • 파이프, 필터 등과 같이 가드도 컨트롤러, 메서드, 글로벌 스코프로 사용될 수 있다.
    • @UseGuards() 데코레이터를 이용하거나 useGlobalGuads()로 글로벌로 등록한다.
    • 글로벌 가드 역시 DI를 활용하기 위해 모듈로 등록할 수 있다
      import { Module } from '@nestjs/common';
      import { APP_GUARD } from '@nestjs/core';
      
      @Module({
      providers: [
      		{
      		provide: APP_GUARD,
      		useClass: RolesGaurd,
      		},
      	],
      })
      export class AppModule {}
  5. Setting roles per handler
    • monorepo 예시
    • metadata를 설정하는 데코레이터를 생성
      import { SetMetadata } from '@nestjs/common';
      import { AdminLevel } from '@libs/shared/constants/services/admin/admin.db';
      
      export const ALLOW_ADMIN_LEVEL = 'ALLOW_ADMIN_LEVEL';
      
      export const AllowAdminLevel = (adminLevel: AdminLevel) =>
        SetMetadata(ALLOW_ADMIN_LEVEL, adminLevel);
    • @AllowAdminLevel 데코레이터를 이용하여 AdminLevel을 실행환경에 설정하며 가드에서 사용할 수 있게함.
      @UseGuards(AdminLevelGuard)
        @AllowAdminLevel(AdminLevel.Master)
        @Post()
        async create(
          @AdminLogin() loggedInAdmin: Admin,
          @Body() createAdministratorDto: CreateAdministratorDto,
        ) {
          const existAdmin = await this.administratorsService.findOneBy({
            email: createAdministratorDto.email,
          });
      
          if (existAdmin) {
            throw new BadRequestException(
              HTTP_RESPONSE_ERROR_CODE.ADMINISTRATOR.ADMINISTRATOR007,
            );
          }
      
          const administrator = await this.administratorsService.create(
            loggedInAdmin,
            createAdministratorDto,
          );
      
          return new BaseResponseDto(administrator);
        }
profile
하루하루 차근차근

0개의 댓글