안녕하세요. NestJS에서 인증을 구현하는 방법에 대해 알아보려고 합니다.
개발을 하다 보면 '인증'과 '인가'라는 용어를 자주 마주치게 되는데요, 이 둘은 비슷하면서도 명확히 다른 개념입니다.
인증(Authentication)은 쉽게 말해 "너 누구야?"라고 물어보는 거예요. 우리가 서비스에 로그인할 때처럼, 사용자가 자신이 주장하는 사람이 맞는지 확인하는 과정입니다.
인가(Authorization)는 "너 이거 할 수 있어?"라고 물어보는 거예요. 예를 들어, 관리자만 접근할 수 있는 페이지에 일반 사용자가 들어가려고 할 때 체크하는 것처럼요.
NestJS에서는 여러 가지 인증 방식을 사용할 수 있는데요, 각각의 특징을 살펴보면서 어떤 상황에서 어떤 방식을 선택하면 좋을지 이야기해보려고 합니다.
JWT는 요즘 가장 많이 사용되는 인증 방식인데요, 토큰 기반으로 동작합니다.
JWT는 마치 신분증같은 거예요. Header(신분증 형식), Payload(실제 정보), Signature(위조 방지 장치)로 구성되어 있죠. Base64로 인코딩되어 점(.)으로 구분된 문자열 형태로 만들어집니다.
세션은 전통적인 방식이지만, 여전히 많이 사용되고 있어요. 특히 서버에서 렌더링하는 웹사이트에서는 아직도 강력한 선택지죠.
OAuth 2.0은 요즘 많이 보시는 '구글로 로그인하기', '카카오로 로그인하기' 같은 기능을 구현할 때 사용하는 표준 프로토콜이에요.
API 키는 주로 서버와 서버 사이, 또는 개발자용 API를 제공할 때 많이 사용하는 방식이에요.
자, 이제 NestJS에서 실제로 JWT 인증을 구현하는 방법을 알아볼게요. JWT를 선택한 이유는 현재 가장 많이 사용되는 방식이기도 하고, NestJS 공식 문서에서도 가장 자세히 다루고 있기 때문입니다.
npm install @nestjs/jwt @nestjs/passport passport passport-jwt
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
@Injectable()
export class AuthService {
constructor(private readonly jwtService: JwtService) {}
async login(user: any) {
const payload = { sub: user.id, username: user.username };
// 실제 서비스에서는 이렇게 토큰 두 개를 발급해요
return {
accessToken: this.jwtService.sign(payload, { expiresIn: '15m' }),
refreshToken: this.jwtService.sign(payload, { expiresIn: '7d' }),
};
}
async validateUser(username: string, password: string) {
// 실제로는 DB에서 사용자를 찾아야 해요
if (username === 'test' && password === 'password') {
return { id: 1, username };
}
return null;
}
}
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_SECRET,
});
}
async validate(payload: any) {
return { userId: payload.sub, username: payload.username };
}
}
import { Controller, Get, UseGuards, Request } from '@nestjs/common';
import { JwtAuthGuard } from './jwt-auth.guard';
@Controller('profile')
export class ProfileController {
@UseGuards(JwtAuthGuard)
@Get()
getProfile(@Request() req) {
return req.user;
}
}
실제 서비스에서는 보안을 더 강화할 필요가 있습니다. 간단히 아래와 같은 방법들이 있어요.
지금까지 NestJS에서 인증을 구현하는 여러 가지 방법을 알아봤는데요, 마무리로 인증 방식 선택 가이드를 가볍게 정리해보록 하겠습니다.
실제로 구현하실 때는 프로젝트의 특성을 잘 고려해서 선택해야겠다는 생각이 듭니다~!