반응형
가드란

 

가드는 라우팅된 핸들러(컨트롤러의 메서드)에 도달하기 전에 실행되는 중간에 위치하는 기능입니다.

이중 CanActivate라는 가드에 대해 알아볼 것 입니다.

CanActivate가드는 NestJS에서 사용되는 가드 중 하나이며, 주로 라우트로의 접근을 허용 또는 거부하는데 사용합니다.

 

사용방법

 

CanActivate를 구현한 클래스는 반드시 canActivate 메서드를 모함해야합니다.

 

이 메서드는 true를 요청하면 요청을 계속 진행하고, false를 반환하면 요청이 중단되어 forbidden오류가 발생합니다.

 

사용예시

 

아래는 제가 사용한 예시입니다.

/* /src/auth/auth.guard.ts */

//request를 진행할지 말지 결정

import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { GqlExecutionContext } from '@nestjs/graphql';
import { Observable } from 'rxjs';
import { ErrorCode } from 'src/common/types/exception.types';
import { CustomError } from 'src/HttpExceptionFilter';
import { User } from 'src/users/entities/user.entity';
import { AllowedRoles } from './role.decorator';

//미들웨어 > 가드 > route
@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {}
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const roles = this.reflector.get<AllowedRoles>(
      'roles',
      context.getHandler(),
    );
    if (!roles) {
      //모두 접근이 가능한 페이지
      return true;
    }
    const gqlContext = GqlExecutionContext.create(context).getContext();
    const user: User = gqlContext.req.user;
    if (!user) {
      throw new CustomError(ErrorCode.UNAUTHORIZED);
    }
    if (roles.includes('Any')) {
      //모두 접근이 가능한페이지
      return true;
    }

    //접근이 가능한경우 true 아닌경우 false로 인해 forbidden에러 발생
    return roles.includes(user.role);
  }
}

 

 

/* /src/auth.module.ts */

import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';
import { AuthGuard } from './auth.guard';

//모든 요청에서 Guard를 확인함
@Module({ providers: [{ provide: APP_GUARD, useClass: AuthGuard }] })
export class AuthModule {}

 

 

/* /src/auth/role.decorator.ts */
/* 유저 롤을 구분하기 위해 사용하며 롤은 Client, Owner, Delivery 밑에 추가되는 Any 총 4개이다 */

import { SetMetadata } from '@nestjs/common';
import { UserRole } from 'src/users/entities/user.entity';

export type AllowedRoles = keyof typeof UserRole | 'Any';
export const Role = (roles: AllowedRoles[]) => SetMetadata('roles', roles);

 

 

/* /src/app.bodule.ts */
/* AuthModule을 Import해준다 */

생략
///
	import:[AuthModule,
    생략///]

///
생략

 

/* /src/users/users.resolver.ts */
/* Role Decorator가 없으면 모든 사용자 접근 가능 */
/* Role Decorator가 있는 경우, auth.guard.ts 소스 로직에 따라 동작함. */


import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
import { AuthUser } from 'src/auth/auth-user.decorator';
import { Role } from 'src/auth/role.decorator';
import {
  CreateAccountInput,
  CreateAccountOutput,
} from './dtos/create-account..dto';
import { EditProfileInput, EditProfileOutput } from './dtos/edit-profile.dto';
import { LoginInput, LoginIOutput } from './dtos/login.dto';
import { UserProfileInput, UserProfileOutput } from './dtos/user-profile.dto';
import { VerifyEmailInput, VerifyEmailOutput } from './dtos/verify-email.dto';
import { User } from './entities/user.entity';
import { UsersService } from './users.service';
/* eslint-disable */

@Resolver(of => User)
export class UsersResolver {
  constructor(private readonly userService: UsersService) {}

  @Mutation(returns => CreateAccountOutput)
  createAccount(
    @Args('input') createAccountInput: CreateAccountInput,
  ): Promise<CreateAccountOutput> {
    return this.userService.createAccount(createAccountInput);
  }

  @Role(['Any'])
  @Query(returns => UserProfileOutput)
  userProfile(
    @Args() userProfileInput: UserProfileInput,
  ): Promise<UserProfileOutput> {
    return this.userService.findById(userProfileInput.userId);
  }

}

 

반응형

+ Recent posts