@User() 같은 커스텀 데코레이터로 요청 헤더의 JWT를 받아오는 방법을 정리합니다.authorization에서 토큰을 꺼내고, 토큰을 디코딩해 request.user에 넣은 뒤, 커스텀 파라미터 데코레이터로 컨트롤러에서 꺼내 씁니다.@User() user: UserInfo 한 줄로 사용자 정보를 받아 쓸 수 있습니다.요청 헤더에 담겨 오는 JWT를 컨트롤러마다 직접 파싱하면 코드가 반복됩니다. 토큰을 꺼내고 디코딩하는 로직을 한곳에 모아두고, 컨트롤러에서는 @User() 데코레이터로 사용자 정보만 받아 쓰도록 만들어 보겠습니다.
실행 절차는 다음과 같습니다.
먼저 AppModule의 provider에 APP_INTERCEPTOR를 추가해 인터셉터를 전역으로 등록합니다. useClass로 어떤 클래스를 인터셉터로 사용할지 지정합니다. (UserInterceptor는 아직 만들지 않았으며, 아래처럼 interceptors 폴더를 만들어 관련 로직을 처리합니다.)
//main.ts @Module({ imports: [UserModule, PrismaModule, HomeModule], controllers: [AppController], providers: [ AppService, { provide: APP_INTERCEPTOR, useClass: UserInterceptor }, ], }) export class AppModule {}
NestInterceptor를 구현해 인터셉터 클래스를 만듭니다. context.switchToHttp().getRequest()로 요청 정보를 가져온 뒤, headers의 authorization에서 토큰을 꺼내고, 디코딩한 결과를 request.user에 넣습니다.
//src/user/interceptors/user.interceptor.ts import { CallHandler, ExecutionContext, NestInterceptor } from '@nestjs/common'; import { Observable } from 'rxjs'; import * as jwt from 'jsonwebtoken'; export class UserInterceptor implements NestInterceptor { intercept( context: ExecutionContext, next: CallHandler<any>, ): Observable<any> | Promise<Observable<any>> { const request = context.switchToHttp().getRequest(); const token = request?.headers?.autorization.split('Bearer ')[1]; const user = jwt.decode(token); request.user = user; return next.handle(); } }
NestInterceptor를 구현해 인터셉터용 클래스를 만듭니다.context.switchToHttp().getRequest()로 요청 정보를 가져옵니다.createParamDecorator로 파라미터 데코레이터를 만듭니다. 인터셉터에서 request.user에 넣어 둔 값을 그대로 반환합니다.
//src/decorators/user.decorator.ts import { createParamDecorator, ExecutionContext } from '@nestjs/common'; export interface UserInfo { name: string; id: number; iat: number; exp: number; } export const User = createParamDecorator((context: ExecutionContext) => { const request = context.switchToHttp().getRequest(); return request.user as UserInfo; });
UserInterceptor에서 만들어 준 user 정보를 반환합니다. (request에 user 정보를 넣어 줬기 때문입니다.)@Post() createHome(@Body() body: CreateHomeDto, @User() user: UserInfo) { return this.homeService.createHome(body, user.id); }
인터셉터에서 JWT를 한 번만 디코딩해 request.user에 담아 두면, 컨트롤러는 @User() 데코레이터로 사용자 정보를 간결하게 받아 쓸 수 있습니다. 토큰 파싱 로직이 한곳에 모이고 컨트롤러는 비즈니스 로직에 집중할 수 있습니다.