기술과 산업/언어 및 프레임워크
NestJS 마스터 시리즈 16화. 인증 시스템 구현 (2) – AuthGuard와 역할 기반 인가 처리
B컷개발자
2025. 5. 28. 12:55
728x90
"보안은 인증으로 시작하고, 인가로 완성된다"
NestJS에서 JWT 인증 이후의 권한 제어를 구현하는 방법을 설명합니다. AuthGuard 설정, 커스텀 데코레이터, RolesGuard 패턴을 기반으로 실무에서 활용되는 인가 전략을 단계별로 소개합니다.
인증과 인가의 차이
- 인증(Authentication): 누구인지 확인하는 과정
- 인가(Authorization): 무엇을 할 수 있는지 결정하는 권한 부여 과정
이번 회차에서는 인증된 사용자에게 API 사용 권한을 어떻게 제한하고 제어할 것인지를 다룬다.
1. JWT 기반 AuthGuard 설정
NestJS는 Passport의 JWT 전략을 기반으로 AuthGuard('jwt')를 사용하여 인증 보호 API를 쉽게 구성할 수 있다.
import { UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@UseGuards(AuthGuard('jwt'))
@Get('profile')
getProfile(@Request() req) {
return req.user;
}
- 사용자는 Authorization: Bearer <token> 헤더를 포함해야 한다.
- 유효하지 않으면 자동으로 401 Unauthorized 응답 반환
2. 역할 기반 인가 처리 – @Roles() + RolesGuard
실무에서는 관리자(Admin), 일반 사용자(User), 게스트(Guest) 등 역할에 따른 접근 제어가 필요하다.
1) 커스텀 데코레이터: @Roles()
import { SetMetadata } from '@nestjs/common';
export const ROLES_KEY = 'roles';
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
- NestJS의 SetMetadata()를 통해 라우트에 메타데이터를 설정
2) RolesGuard 구현
import {
Injectable,
CanActivate,
ExecutionContext,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
@Injectable()
export class RolesGuard implements CanActivate {
constructor(private reflector: Reflector) {}
canActivate(context: ExecutionContext): boolean {
const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
context.getHandler(),
context.getClass(),
]);
if (!requiredRoles) return true;
const { user } = context.switchToHttp().getRequest();
return requiredRoles.includes(user.role);
}
}
- 요청 핸들러에서 정의한 역할이, 현재 사용자 역할과 일치하는지 검사한다.
- 일치하지 않으면 403 Forbidden 응답
3. 실제 API에 Guard 적용
@UseGuards(AuthGuard('jwt'), RolesGuard)
@Roles('admin')
@Get('admin/users')
findAllUsers() {
return this.usersService.findAll();
}
- JWT로 인증된 사용자 중, role === 'admin' 인 사용자만 접근 가능
- 일반 사용자가 접근하면 403 응답 발생
4. 사용자 정보에 역할 포함시키기
JWT 발급 시, 사용자 역할도 payload에 포함시켜야 한다.
const payload = { username: user.email, sub: user.id, role: user.role };
JwtStrategy에서도 payload에서 역할을 복원한다:
async validate(payload: any) {
return {
id: payload.sub,
email: payload.username,
role: payload.role,
};
}
5. 실무 적용 전략 요약
기능 구현 방식
인증 보호 | @UseGuards(AuthGuard('jwt')) |
역할 제한 | @UseGuards(RolesGuard), @Roles() |
역할 분기 처리 | 사용자 모델에 role 필드 포함 |
유연한 구성 | @SetMetadata() + Reflector 조합 |
인증은 사용자를 확인하고, 인가는 사용자의 행동을 제한한다
마무리 인사이트
NestJS는 Passport와 Guard 시스템을 통해
**역할 기반 인가 처리(RBAC: Role-Based Access Control)**를 유연하게 구현할 수 있게 설계되어 있다.
- 인증은 토큰 기반으로 보안성을 확보하고
- 인가는 데코레이터와 Guard를 통해 흐름을 분기시킨다
이 구조를 잘 설계하면 코드가 복잡해지지 않으면서도 강력한 보안 구조를 유지할 수 있다.
"인가 로직을 코드 안에 심는 대신, 구조로 표현하라"
다음 회차 예고
NestJS 마스터 시리즈 17화. 커스텀 데코레이터 만들기 – @User()와 @Roles()를 구조화하다
반복되는 인증/인가 코드를 줄이기 위한 커스텀 데코레이터 설계와 적용 전략을 소개합니다.
728x90