개요

가드 Guard를 이용해 NestJS 애플리케이션을 위험한 요청으로부터 차단하는 방법 정리 컨트롤러에 도달하기 전 단계에서 인증과 접근 제어 수행하는 패턴 중심으로 설명

가드란

NestJS에서 가드는 애플리케이션에 들어오는 요청을 컨트롤러로 보내기 전에 통과 여부를 결정하는 구성 요소 미들웨어와 유사한 역할이지만 라우트 핸들러 실행 여부를 명시적으로 결정하는 책임에 초점 요청 수명주기에서 미들웨어 다음, 컨트롤러 이전에 실행됨 canActivate가 true 또는 Promise을 반환하면 다음 단계로 진행, false면 기본적으로 403 Forbidden 응답 발생

프로젝트 준비

Nest CLI로 샘플 프로젝트 생성

$ nest new our-nestjs

패키지 매니저 선택 후 기본 템플릿 생성됨

가드로 요청 전달

CanActivate 인터페이스 구현으로 가드 정의

import { Injectable, CanActivate } from "@nestjs/common";

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate() {
    return true;
  }
}

canActivate가 true를 반환하므로 요청은 컨트롤러로 전달됨

컨트롤러에 가드 적용

UseGuards 데코레이터로 클래스 또는 메서드 단위 적용 가능

import { Controller, Get, UseGuards } from "@nestjs/common";

@UseGuards(AuthGuard)
@Controller()
export class AppController {
  @Get()
  getHello() {
    return "Hello World!";
  }
}

curl로 확인

$ curl http://localhost:3000
Hello World!

가드로 요청 차단

반대로 false를 반환하면 요청은 차단되고 403 Forbidden 응답

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate() {
    return false;
  }
}
$ curl http://localhost:3000
{"message":"Forbidden resource","error":"Forbidden","statusCode":403}

가드로 인증 구현

ExecutionContext로 HTTP 요청 객체에 접근해 헤더 등 입력값 검사 가능 Bearer 토큰을 단순 검증하는 예시

import {
  CanActivate,
  ExecutionContext,
  BadRequestException,
  Injectable,
} from "@nestjs/common";

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext) {
    const req = context.switchToHttp().getRequest();
    const auth = req.headers["authorization"] as string | undefined;
    if (!auth) throw new BadRequestException();
    const [scheme, token] = auth.split(" ");
    return scheme?.toLowerCase() === "bearer" && token === "1234";
  }
}

의미

  • Authorization 헤더가 없으면 BadRequestException 발생해 400 응답
  • Bearer 스킴이며 토큰이 1234일 때만 통과

실서비스에서는 다음 중 하나 이상 필요

  • 토큰으로 사용자 조회 또는 권한 검증
  • 서드파티 인증 서버 연동 또는 캐시 검증
  • JWT 디코딩 및 서명 검증

인증 가드 테스트

잘못된 토큰이면 403

$ curl -H "Authorization: Bearer 1111" http://localhost:3000
{"message":"Forbidden resource","error":"Forbidden","statusCode":403}

올바른 토큰이면 성공

$ curl -H "Authorization: Bearer 1234" http://localhost:3000
Hello World!

헤더가 없으면 400

$ curl http://localhost:3000
{"message":"Bad Request","statusCode":400}

주의와 베스트 프랙티스

  • 가드는 인증·인가 같은 접근 제어에 집중, 복잡한 비즈니스 로직은 서비스로 위임
  • 공통 검증은 글로벌 가드로 등록해 중복 제거
  • 반환형은 boolean 또는 Promise 사용, 명시적 예외는 Exception 클래스로 던짐
  • 로깅은 콘솔 대신 프레임워크 로거 사용 권장
  • 세분화된 역할 검증은 메타데이터와 커스텀 데코레이터 조합으로 역할 기반 가드 구성 권장

마무리

Guard는 컨트롤러 앞단에서 요청을 선별하는 확실한 진입점 제공 간단한 구현만으로도 인증과 접근 제어의 기본선을 세울 수 있음 실서비스에서는 토큰 검증, 캐시, 외부 인증 연동을 조합해 성능과 보안의 균형을 맞출 것

참고자료