낙서장이자 오답 노트이자 컨닝 페이퍼
패스트캠퍼스 환급챌린지 28일차 : 코드팩토리의 백엔드 아카데미 : 한 번에 끝내는 NestJS 패키지 - 기초부터 MSA까지 강의 후기 본문
패스트캠퍼스 환급챌린지 28일차 : 코드팩토리의 백엔드 아카데미 : 한 번에 끝내는 NestJS 패키지 - 기초부터 MSA까지 강의 후기
NangIn 2025. 4. 28. 18:56본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.
강의 내용 정리
passport 이론
Passport란 무엇인가?
- 모듈화된 인증 시스템
- 다양한 인증 방식을 유연하게 연결
- ex) 이메일/비밀번호, 구글 로그인 등
- 코드량을 줄일 수 있는 장점
- 복잡한 인증 로직을 전략으로 추상화해 둔 덕분
- 미들웨어 기반
- 기존 코드에 비파괴적으로 통합 가능
- 코어는 가볍고 일반화된 구조
- 다양한 전략을 끼워 넣을 수 있게 설계됨
- 세션 방식과 토큰 방식 모두 지원
- 전략마다 방식이 다를 뿐, Passport 자체는 모두 지원
- 풍부한 생태계
- 수많은 전략 패키지 존재 (ex. passport-local, passport-jwt, passport-google 등)
패스포트 사용 시 주의점
| 장점 | 단점 |
| 인증 코드 작성이 간편 | 추상화로 인해 유연성 부족 |
| 다양한 전략 즉시 활용 가능 | 내부 동작을 정확히 파악하지 않으면 디버깅 어려움 |
| 미들웨어 형태로 쉽게 통합 | 특정 프로젝트와 맞지 않을 수 있음 |
Passport 사용 방식 요약
- 전략(Strategy) 구현
- 예: LocalStrategy, JwtStrategy
- validate() 메서드를 필수로 구현해야 함
- 이 안에서 인증 로직 작성 (ex. 유저 검증, 비밀번호 비교 등)
- 전략 주입
- @Injectable()로 NestJS에서 DI로 사용
- PassportStrategy()를 확장하여 사용
- Guard로 적용
- AuthGuard('local') → 해당 전략(LocalStrategy) 적용
- 전략 이름은 커스터마이징 가능
- JWT 전략으로 바꾸려면 'jwt'만 지정해주면 됨
@UseGuards(AuthGuard('local'))
패스포트를 쓰는 이유 vs 쓰지 않는 이유
- Passport 사용 장점
- 인증에 필요한 로직을 거의 직접 작성하지 않아도 됨
- 전략 교체가 간편 (JWT ↔︎ Local 등)
- Passport 사용 단점
- 추상화가 많아 직접 제어가 어려움
- 자유도가 낮아 세세한 커스터마이징이 어렵고
- 프로젝트 요구사항에 따라 과한 복잡성을 유발할 수 있음
Local Strategy 적용하기
Passport 관련 패키지 설치
pnpm i @nestjs/passport passport passport-local
pnpm i -D @types/passport-local
- @nestjs/passport: NestJS에서 Passport 전략을 쉽게 쓰도록 도와주는 모듈
- passport: 기본 Passport.js
- passport-local: Local 전략용
- @types/passport-local: 타입 지원
전략 디렉토리 및 Local Strategy 생성
- /auth/strategy/local.strategy.ts 생성
- 전략 클래스 기본 구성:
-
@Injectable() export class LocalStrategy extends PassportStrategy(Strategy) { constructor(private authService: AuthService) { super({ usernameField: 'email' }); // 기본값은 username } async validate(email: string, password: string): Promise<User> { return this.authService.authenticate(email, password); } } - usernameField 변경: 기본은 username, email로 지정 가능
- validate는 자동 호출되는 콜백 → 여기서 유저 검증 수행
-
AuthService에 검증 로직 분리
- 기존 로그인 로직에서 유저 검증 부분만 함수로 분리:
async authenticate(email: string, password: string): Promise<User> {
const user = await this.userRepository.findOne({ where: { email } });
if (!user) throw new BadRequestException('잘못된 로그인 정보입니다.');
const passOk = await bcrypt.compare(password, user.password);
if (!passOk) throw new BadRequestException('잘못된 로그인 정보입니다.');
return user;
}
Guard로 적용하기
- 기본 방식 (문자열 사용):
@UseGuards(AuthGuard('local'))
@Post('login-passport')
loginPassport(@Request() req) {
return req.user; // validate에서 반환된 유저
}
- 전용 Guard로 추출 (오타 방지):
export class LocalAuthGuard extends AuthGuard('local') {}
@UseGuards(LocalAuthGuard)
@Post('login-passport')
loginPassport(@Request() req) {
return req.user;
}
학습 후기
NestJS에서 인증 시스템을 구축하면서 Passport를 적용해보니, 단순히 "전략을 등록해서 Guard로 감싼다"는 문법 이상의 통찰이 생겼습니다. Passport는 단순한 인증 라이브러리가 아니라, 인증 방식을 추상화하고 전략적으로 분리할 수 있도록 도와주는 플러그인 시스템에 가까운 구조입니다.
Local Strategy를 적용하면서 느낀 가장 큰 장점은 인증 흐름이 명확해진다는 점입니다. 기존에는 로그인 요청에서 이메일, 비밀번호를 직접 검증하고 응답하는 코드가 라우터에 함께 존재했다면, 전략으로 분리한 후에는 validate() 메서드에 인증 책임을 위임할 수 있었습니다. 이 덕분에 인증 로직과 라우팅 로직의 관심사가 명확히 분리되었고, 테스트하기도 쉬워졌습니다.
또한 AuthGuard('local')과 같이 전략을 문자열로 지정하여 사용할 수 있고, 이를 별도의 Guard 클래스로 추출해 관리하면 전략 이름 오타를 방지할 수 있으며 재사용성도 높아졌습니다. 특히, usernameField를 email로 변경해 Postman 테스트에서도 혼란 없이 진행할 수 있었고, 실제 전략 간 전환(JWT ↔ Local)도 매우 간편했습니다.
물론 단점도 있었습니다. Passport는 전략 내부 동작이 추상화되어 있어, 처음에는 흐름을 따라가기 어렵고 디버깅이 복잡하게 느껴졌습니다. 특히 NestJS에서 Guard가 validate() 결과를 자동으로 req.user에 실어주는 구조는 문서를 보지 않으면 파악하기 어려운 부분이었습니다. 하지만 내부 흐름을 이해한 후에는 오히려 일관된 인증 구조를 구성할 수 있다는 장점으로 다가왔습니다.
이번 학습을 통해 느낀 가장 중요한 점은, 인증은 단순히 로그인 여부를 판단하는 절차가 아니라, 애플리케이션의 전반적인 보안 흐름을 설계하는 것이라는 사실입니다. Passport를 도입함으로써 인증 전략을 별도로 설계하고, 확장성과 테스트 가능성을 확보할 수 있었던 점이 매우 인상 깊었습니다. 앞으로 JWT 전략까지 결합하면 더 강력한 인증 시스템을 구축할 수 있을 것으로 기대됩니다.
학습 인증샷



