-
NestJS 마스터 시리즈 15화. 인증 시스템 구현 (1) – JWT 기반 로그인 시스템 만들기기술과 산업/언어 및 프레임워크 2025. 5. 27. 14:22728x90
"인증은 단순한 로그인이 아니라, 서비스와 사용자 사이의 신뢰 계약이다"
NestJS에서 JWT 인증 시스템을 구현하는 방법을 설명합니다. PassportModule 연동, JWT 전략 구성, 로그인 및 토큰 발급 로직까지 실무 수준으로 정리합니다.
인증이란 무엇인가?
- 인증(Authentication): 사용자가 누구인지 확인하는 과정
- 인가(Authorization): 인증된 사용자가 특정 리소스에 접근할 수 있는지 판단하는 과정
이번 글에서는 먼저 인증, 특히 로그인과 토큰 발급 흐름에 집중한다.
1. 필요한 패키지 설치
npm install @nestjs/passport @nestjs/jwt passport passport-jwt npm install --save-dev @types/passport-jwt
- passport: 인증 전략을 통합 관리하는 미들웨어
- passport-jwt: JWT 인증 전략 모듈
- @nestjs/jwt: NestJS용 JWT 발급 및 검증 유틸
2. AuthModule 구성
nest generate module auth nest generate service auth nest generate controller auth
auth.module.ts에 다음과 같이 JWT 모듈을 등록한다.
@Module({ imports: [ JwtModule.register({ secret: 'jwt-secret-key', // 운영 환경에선 .env로 관리 signOptions: { expiresIn: '1h' }, }), PassportModule, UsersModule, ], providers: [AuthService, JwtStrategy], controllers: [AuthController], }) export class AuthModule {}
3. JwtStrategy 정의
JWT를 검증하고, 사용자 정보를 Request 객체에 주입하는 전략이다.
@Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor(private usersService: UsersService) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'jwt-secret-key', }); } async validate(payload: any) { return this.usersService.findOne(payload.sub); } }
- 토큰에서 sub(사용자 ID) 값을 추출해 DB에서 사용자 정보를 조회
- 컨트롤러에서 @Request()나 @User() 커스텀 데코레이터를 통해 접근 가능
4. AuthService 구현 – 로그인 및 토큰 발급
@Injectable() export class AuthService { constructor( private usersService: UsersService, private jwtService: JwtService, ) {} async validateUser(email: string, password: string): Promise<any> { const user = await this.usersService.findByEmail(email); if (user && user.password === password) { const { password, ...result } = user; return result; } return null; } async login(user: any) { const payload = { username: user.email, sub: user.id }; return { access_token: this.jwtService.sign(payload), }; } }
5. AuthController – 로그인 API 구성
@Controller('auth') export class AuthController { constructor(private authService: AuthService) {} @Post('login') async login(@Body() body: { email: string; password: string }) { const user = await this.authService.validateUser(body.email, body.password); if (!user) { throw new UnauthorizedException('Invalid credentials'); } return this.authService.login(user); } }
요청 예시:
POST /auth/login { "email": "test@example.com", "password": "secure123" }
응답 예시:
{ "access_token": "eyJhbGciOiJIUzI1NiIs..." }
6. 비밀번호 보안 처리 – 실무 기준
현재는 비밀번호를 평문으로 비교하고 있지만, 실제 서비스에서는 bcrypt 등을 사용해 암호화/검증을 수행해야 한다.
npm install bcrypt npm install --save-dev @types/bcrypt
암호화 예시:
const hashed = await bcrypt.hash(password, 10); const isMatch = await bcrypt.compare(inputPassword, hashed);
마무리 인사이트
NestJS + Passport + JWT는 실무에서도 가장 보편적이고 강력한 인증 조합이다.
이 구조를 익히고 나면 이후의 인가 처리, 권한 분리, 토큰 갱신도 자연스럽게 확장할 수 있다.- 인증은 단순한 토큰 발급이 아니라, 서비스 신뢰의 첫 관문
- 구조화된 인증 플로우가 보안과 유지보수를 모두 지킨다
"인증 시스템은 처음부터 구조적으로 시작해야, 나중에 후회하지 않는다"
다음 회차 예고
NestJS 마스터 시리즈 16화. 인증 시스템 구현 (2) – AuthGuard와 역할 기반 인가 처리
JWT 토큰을 활용한 접근 제어, Role 기반 권한 분기, 커스텀 데코레이터 설계까지 설명합니다.728x90'기술과 산업 > 언어 및 프레임워크' 카테고리의 다른 글
Spring Framework 시리즈 7화 – @Value와 Environment로 설정값 주입하기 (0) 2025.05.27 Spring Framework 시리즈 6화 – 의존성 순환 오류 해결 전략 (0) 2025.05.27 전자정부 표준프레임워크 시리즈 10화 – 파일 업로드와 다운로드 처리 구조 분석: EgovFileMngService의 내부 작동 방식 (1) 2025.05.26 Spring Framework 시리즈 5화 – 스프링 빈 스코프 정리 (0) 2025.05.26 Spring Boot 시리즈 36편 – Elasticsearch 연동: 검색 기능 확장을 위한 인덱싱, 매핑, 쿼리 전략 (0) 2025.05.26