728x90

1. ⚔️ Guard란 무엇이며 왜 필요한가요?
가드(Guard)는 특정 라우트(Route)에 접근하는 클라이언트에게 권한이 있는지 확인하여 요청 처리를 허용하거나 거부하는 역할을 합니다. NestJS 파이프라인에서 미들웨어 다음으로 실행되며, Guard가 통과(모두 true 반환)되어야만 요청이 컨트롤러 핸들러로 전달됩니다.
Guard의 주요 역할
- 인증 (Authentication): 요청을 보낸 사용자가 시스템에 로그인된 유효한 사용자인지 확인합니다 (예: JWT 토큰 검증).
- 인가 (Authorization): 로그인된 사용자가 해당 리소스에 접근하거나 특정 작업을 수행할 권한(Role)이 있는지 확인합니다 (예: "관리자만 사용자 삭제 가능").
2. 🏗️ Guard 구현 방법
Guard는 CanActivate 인터페이스를 구현하며, canActivate() 메서드가 핵심 로직을 담당합니다.
728x90
2.1. CanActivate 인터페이스
Guard 클래스는 @Injectable() 데코레이터를 사용하고 CanActivate를 구현합니다.
// auth.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service'; // DI를 위해 서비스 주입
@Injectable()
export class AuthGuard implements CanActivate {
// 💡 DI 컨테이너에서 AuthService를 주입받을 수 있습니다.
constructor(private authService: AuthService) {}
canActivate(
context: ExecutionContext,
): boolean | Promise<boolean> | Observable<boolean> {
// 1. 요청 컨텍스트 가져오기 (HTTP, WebSockets 등)
const request = context.switchToHttp().getRequest();
// 2. 인증 로직 수행 (예: 요청 헤더에서 JWT 추출 및 검증)
const isAuthenticated = this.validateRequest(request);
// 3. 💡 최종적으로 boolean 값을 반환
// true: 요청 처리 계속 진행
// false: 요청 처리 중단 및 HTTP 403 Forbidden 반환
return isAuthenticated;
}
private validateRequest(request): boolean {
// 실제 AuthService의 validateToken 로직을 사용
const token = request.headers.authorization;
return this.authService.validateToken(token);
}
}
2.2. ExecutionContext의 중요성
canActivate() 메서드는 ExecutionContext 객체를 인자로 받습니다. 이 객체는 현재 실행 중인 핸들러(라우트 메서드)에 대한 정보를 담고 있으며, HTTP 외의 다른 컨텍스트(WebSockets, RPC 등)에서도 Guard를 사용할 수 있도록 일반화된 API를 제공합니다.
- context.switchToHttp().getRequest(): 현재 HTTP 요청 객체(req)를 가져옵니다.
3. 📌 Guard 적용 및 실행 순서
Guard는 컨트롤러, 컨트롤러 메서드, 또는 글로벌 레벨에서 @UseGuards() 데코레이터를 사용하여 적용합니다.
3.1. 실행 순서
요청이 들어왔을 때 Guard는 미들웨어 다음, 인터셉터와 파이프보다 먼저 실행됩니다.
- Middleware
- Guard (인증/인가)
- Pipe (데이터 검증/변환)
- Interceptor (요청 전 처리)
- Controller Handle
728x90
3.2. 적용 예시
// users.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '../auth/auth.guard';
import { RolesGuard } from './roles.guard'; // 인가 Guard
@Controller('users')
// 💡 1. 클래스 레벨 적용: 이 컨트롤러의 모든 라우트에 적용됩니다.
@UseGuards(AuthGuard, RolesGuard)
export class UsersController {
@Get() // GET /users
findAll() {
// AuthGuard와 RolesGuard를 통과한 요청만 여기에 도달
}
@Get('public')
// 💡 2. 메서드 레벨 적용: 특정 Guard를 무시하거나 다른 Guard를 추가할 수 있습니다.
@UseGuards() // 비어있는 @UseGuards()로 클래스 레벨 Guard를 오버라이드할 수 있습니다.
findPublic() {
return 'Public access allowed';
}
}
4. 🥇 Guard의 장점: DI 기반의 강력한 인증/인가
Guard의 가장 큰 장점은 NestJS의 DI 시스템 내에서 작동한다는 것입니다.
- Guard는 생성자를 통해 AuthService, UsersService 등 복잡한 비즈니스 로직을 가진 서비스를 안전하게 주입받아 사용할 수 있습니다.
- 이는 인증/인가 로직을 재사용 가능한 서비스에 분리하여, 테스트하기 쉽고 유지보수가 용이한 느슨하게 결합된 코드를 만들 수 있게 합니다.
미들웨어가 Express의 낮은 수준의 요청 전처리 도구라면, Guard는 NestJS의 아키텍처 원칙(DI)에 부합하는 권한 처리의 표준 방법입니다.
728x90
'Nest.js를 배워보자 > 6. NestJS Middleware , Guard , Intercept' 카테고리의 다른 글
| Custom Pipe 만들기 (0) | 2025.12.02 |
|---|---|
| Interceptor (인터셉터): 로깅, 응답 변형, 캐싱 (0) | 2025.12.02 |
| Middleware (미들웨어): 요청 가공 및 전처리 (0) | 2025.12.02 |