반응형
가드란
가드는 라우팅된 핸들러(컨트롤러의 메서드)에 도달하기 전에 실행되는 중간에 위치하는 기능입니다.
이중 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);
}
}
반응형
'BackEnd > Nest' 카테고리의 다른 글
[NestJS] GraphQL Subscription설정 (0) | 2024.01.31 |
---|---|
[NestJS] TypeORM > CustomRespository 사용방법 (2) | 2024.01.21 |
[Nest]네스트JS에서 GraphQL 에러 다루기 [Formmat]: 기록 (0) | 2024.01.20 |
[Nest.js] Jest > e2e테스트 detectOpenHandles (0) | 2024.01.20 |
TypeORM 설치 (0) | 2024.01.13 |