NestJS 기초 (13) JWT를 사용한 인증 인가 처리와 데코레이터 구현

2022. 11. 1. 23:47·개발/NestJS

이번 포스팅에서는 JWT를 사용하여 사용자의 인증 및 인가를 처리하고 이를 데코레이터로 구현하여 가드로 활용하는 방법에 대해 알아보도록 하겠습니다.

JWT 기본 개념

JWT는 Jason Web Token의 약자로 두 주체가 안전한 방식으로 클레임(claims)을 주고 받는 방법입니다. JWT에 포함된 클레임은 JSON 객체로 인코딩되는데요. 공식 웹사이트인 Jwt.io에서 JWT를 인코딩 또는 디코딩해볼 수 있습니다.

JWT 구성

JWT를 구현하기 전에 JWT를 사용하기 위해 알아야 할 기본 구성에 대해 살펴보도록 하겠습니다. JWT는 크게 3가지 요소인 헤더, 페이로드, 서명으로 구성되는데요. 각 요소는 .으로 구분합니다.

헤더(header)

헤더에는 JWT 유형과 알고리즘이 담깁니다.

{
    "typ": "JWT",
    "alg": "HS256"
}

페이로드(payload)

페이로드에는 클레임 정보가 담깁니다.

{
    "iss": "발급자",
    "sub": "클레임 설명",
    "aud": "수신자",
    "exp": "만료 시간",
    "nbf": "토큰 활성화 시점",
    "iat": "토큰 발급 시점",
    "jti": "JWT 토큰 식별자"
}

서명(signature)

서명은 생성한 토큰이 유효한지 검증합니다. 헤더에서 "alg": "HS256"이라고 알고리즘을 지정했다면, 해당 방식으로 암호화해야 합니다.

 

여기서 중요한 것은 서명은 토큰의 유효성을 검사할 뿐이지 페이로드를 암호화하는 것이 아니라는 점입니다.

 

따라서 클레임에는 비밀번호와 같은 민감한 정보를 포함해서는 안 됩니다.

NestJS에서 JWT 구현하기

이제 NestJS에서 JWT를 구현하는 방법에 대해 살펴보도록 하겠습니다. 먼저, jwt 패키지를 설치해줍니다.

$ npm install --save @nestjs/jwt passport-jwt
$ npm install --save -dev @types/passport-jwt

다음으로 모듈에 다음과 같이 JwtModule을 임포트해줍니다.

//auth.module.ts

@Module({
  imports: [
    JwtModule.registerAsync({
      useFactory: () => ({
        secret: process.env.AUTH_SECRET,
        signOptions: {
          expiresIn: '30m',
        },
      }),
    }),
  ],
  controllers: [AuthController],
  providers: [AuthService],
})
export class AuthModule {}

간단한 사용자 로그인 정보를 받아 토큰을 발급받아 보겠습니다. 먼저, 컨트롤러에 login 라우터를 하나 만들어보겠습니다.

// auth.controller.ts

@Controller('auth')
export class AuthController {
  constructor(private readonly authService: AuthService) {}

   @Post('login')
  async getTokenForUser(@Body() body) {
    return this.authService.getTokenForUser(body);
  }
}

이제 서비스를 구현할 차례입니다. 아래 코드는 컨트롤러에서 전달받은 username과 email을 jwt 페이로드에 담아 전달합니다.

// auth.service.ts

@Injectable()
export class AuthService {
  constructor(private readonly jwtService: JwtService) {}

  public getTokenForUser(user: User): string {
    return this.jwtService.sign({
      username: user.username,
      email: user.email,
    });
  }
}

포스트맨에서 요청을 테스트해보면 아래와 같이 정상적으로 코드가 발급된 것을 확인할 수 있습니다.

이제 jwt 홈페이지로 이동하여 해당 토큰을 디코딩하면 페이로드에 담았던 정보를 확인할 수 있습니다.

NestJS에서 JWT 디코딩하기

발급한 토큰은 어떻게 디코딩할 수 있을까요? 먼저, 아래와 같이 jwt 토큰을 디코딩해 줄 strategy 파일을 생성합니다.

// jwt.strategy.ts
​
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt';
import { AuthService } from './auth.service';
​
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
  constructor(private authService: AuthService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      ignoreExpiration: true,
      secretOrKey: process.env.AUTH_SECRET,
    });
  }
​
  // 위 로직을 통과하면 아래의 validate 함수가 실행됨 
  async validate(payload) {
    return payload;
  }
}

이후 컨트롤러로 이동하여 가드를 추가해줍니다.

// auth.controller.ts
​
@Get('profile')
@UseGuards(AuthGuard('jwt'))
async authTest(@Req() req) {
  return req.user;
}

포스트맨에서 발급받은 코드를 넣고 실행해보면 다음과 같이 정상적으로 페이로드 부분을 획득할 수 있는 것을 확인할 수 있습니다.

커스텀 데코레이터 만들기

구현한 가드를 커스텀 데코레이터로 사용하여 원하는 곳에서 사용할 수도 있습니다. decorators 디렉토리를 하나 만들어주고, get-user.decorator.ts 파일을 하나 만들어주겠습니다.

//get-user.decorator.ts

import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { User } from '../../users/schemas/users.schema';

export const GetUser = createParamDecorator(
  (data, ctx: ExecutionContext): User => {
    const req = ctx.switchToHttp().getRequest();
    return req.user;
  },
);

이제 앞서 가드를 사용했던 컨트롤러 파일로 이동하여 새롭게 구성한 데코레이터를 임포트하여 사용할 수 있습니다.

@Get('profile')
@UseGuards(AuthGuard('jwt'))
async authTest(@GetUser() user: User) {
  console.log(user);
  return user;
}

 

참고 자료

  • NestJS에서 JWT 발급 및 인증 처리하기

 

'개발 > NestJS' 카테고리의 다른 글

NestJS 기초 (14) 이미지 파일 업로드하기  (0) 2022.11.07
NestJS 기초 (12) 가드를 사용한 인증과 인가  (0) 2022.10.17
NestJS 기초 (11) API 문서 작성하기 (스웨거)  (0) 2022.10.10
'개발/NestJS' 카테고리의 다른 글
  • NestJS 기초 (15) MVC 디자인 패턴 구현하기
  • NestJS 기초 (14) 이미지 파일 업로드하기
  • NestJS 기초 (12) 가드를 사용한 인증과 인가
  • NestJS 기초 (11) API 문서 작성하기 (스웨거)
휘Hwi
휘Hwi
여행, 사진, 개발, 책 이야기를 기록하는 여행자 휘의 블로그 𓂍
Klook.com
  • 휘Hwi
    휘: 끝나지 않은 이야기
    휘Hwi
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 기록
        • 일상 에세이
        • 인사이트
        • 투자와 재테크
        • 코인 이야기
        • 아카이빙
        • 집무실 레터
        • 사랑에 대하여
        • 번역 이야기(完)
        • 프리랜서 일지(完)
      • 여행
        • 🌎 세계 여행기 S1 (完)
        • 🌊 삼삼한 여행기 (完)
        • 🚶 온더로드
        • 🇯🇵 일본
        • 🏝️ 발리
        • 🇻🇳 베트남
        • 🇱🇰 스리랑카
        • 🇮🇳 인도
        • 🇹🇭 태국
        • 🇸🇬 싱가포르
        • 🇦🇺 호주
        • 🇭🇰 홍콩
        • 🇰🇷 한국
        • 🍚 여행자의 한 끼
        • ℹ️ 여행 정보
      • 사진
        • 사진가
        • 사진 이론과 생각
        • 사진 관련 정보
      • 영상
        • 파이널컷 모션 공부
        • 고프로 GoPro
        • 영상 관련 정보
      • 책
        • 책 읽고 쓰기
      • 개발
        • 티스토리
        • Internet
        • HTML
        • CSS
        • JavaScript
        • Typescript
        • React
        • Node.js
        • Express
        • NestJS
        • Python
        • Django
        • MySQL
        • MongoDB
        • AWS
        • Deployment
        • Terminal
        • Git
        • Glossaries
        • Articles
        • Projects
        • TIL;
      • 미분류
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
휘Hwi
NestJS 기초 (13) JWT를 사용한 인증 인가 처리와 데코레이터 구현
상단으로

티스토리툴바