전역 가드에서 주입한 서비스가 undefined였던 이유
문제 발생
인증 가드를 전역으로 걸고 그 안에서 설정 서비스를 쓰려 했습니다.
// main.ts
app.useGlobalGuards(new AuthGuard(configService));configService를 넘길 방법이 마땅치 않아 new ConfigService()를 직접 만들었더니, 앱에서 쓰는 인스턴스와 다른 객체라 값이 비어 있었습니다. 인자 없이 new AuthGuard()로 바꾸자 가드 안에서 this.config가 undefined였습니다.
원인 분석
가드를 우리가 직접 new로 만들었기 때문입니다. NestJS의 DI 컨테이너는 자기가 만든 객체에만 의존성을 넣어줍니다.
문서가 이 제약을 명시합니다 — 어떤 모듈의 바깥에서 useGlobalGuards()로 등록한 전역 가드는 모듈 컨텍스트 밖에서 이루어지는 등록이라 의존성을 주입받을 수 없습니다.
해결책도 함께 있습니다 — 어떤 모듈에서든 아래 구성으로 가드를 직접 설정할 수 있으며, 이 방식으로 DI를 사용할 때 이 구성이 어느 모듈에 있든 그 가드는 실제로 전역입니다.
해결 방안
APP_GUARD토큰으로 provider 등록합니다. 클래스만 넘기므로 인스턴스는 Nest가 만들고, 생성자 주입이 정상 동작합니다.
import { APP_GUARD } from "@nestjs/core";
@Module({
providers: [{ provide: APP_GUARD, useClass: AuthGuard }],
})
export class AppModule {}-
가드를 두 개 이상 걸어도 됩니다. 문서 설명대로
APP_GUARD토큰은 같은 모듈이든 다른 모듈이든 여러 번 등록할 수 있고, 등록한 모든 가드가 매 요청마다 등록 순서대로 실행됩니다. 인증 가드 다음에 역할 가드를 두는 구성이 이 방식입니다. -
APP_FILTER,APP_PIPE,APP_INTERCEPTOR도 같은 규칙입니다. 전역 + DI가 필요하면 전부 provider 등록으로 갑니다. -
전역 가드에 예외 경로를 만드는 방식을 정합니다. 로그인·헬스체크까지 막히므로
@Public()같은 커스텀 데코레이터를 만들고 가드가Reflector로 읽게 합니다. 컨트롤러마다 가드를 다시 붙이는 방식으로 돌아가지 않습니다. -
테스트에서도 이 차이가 드러납니다.
Test.createTestingModule로 만든 앱에는 provider로 등록한 전역 가드가 그대로 붙지만,main.ts의useGlobalGuards는 붙지 않습니다. 테스트에서만 인가가 통과하는 상황이 여기서 생깁니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.