쿠팡이츠 JWT Middleware 적용하기

shooting star·2024년 5월 9일
0
post-thumbnail

들어가며

NestJS를 사용한 웹 애플리케이션에서는 종종 인증 및 권한 부여를 처리하기 위해 JWT(JSON Web Token)를 사용합니다. 이를 효율적으로 구현하기 위해서는 미들웨어(Middleware)를 활용하여 각 요청에서 사용자의 토큰을 검증하고, 유효한 사용자를 식별하는 과정이 필요합니다. 이번 포스트에서는 JWT를 활용한 사용자 인증을 미들웨어로 구현하는 방법을 알아보겠습니다.

미들웨어란 무엇인가?

미들웨어는 요청(request)과 응답(response) 사이에 위치하여 라우트 핸들러 전에 호출되는 함수입니다. 이 함수는 requestresponse 객체에 접근할 수 있고, 애플리케이션의 request-response 주기에 있는 다음(next) 미들웨어 함수로 제어권을 넘길 수 있습니다.

NestJS에서 미들웨어는 익스프레스 미들웨어와 동일한 방식으로 작동하며, 다음 두 가지 형태로 사용자 정의 미들웨어를 구현할 수 있습니다:

  • 함수
  • @Injectable() 데코레이터가 적용된 클래스

자세한 내용은 NestJS 공식 문서 - Middleware에서 확인할 수 있습니다.


JWT 미들웨어 구현하기

JSON Web Token 라이브러리

JWT 토큰을 생성하고 검증하기 위해 jsonwebtoken 패키지를 사용합니다. 먼저 패키지를 설치합니다.

npm i jsonwebtoken
npm i @types/jsonwebtoken -D

JwtService 구현

토큰을 검증하기 위해 JwtService 클래스를 구현합니다. 이 클래스는 토큰을 생성하고, 검증하며 페이로드를 반환하는 역할을 합니다.

import * as jwt from 'jsonwebtoken';
import { Injectable } from '@nestjs/common';

@Injectable()
export class JwtService {
  private readonly secretKey = process.env.SECRET_KEY || 'default_secret';

  sign(payload: any): string {
    return jwt.sign(payload, this.secretKey);
  }

  verify(token: string): any {
    return jwt.verify(token, this.secretKey);
  }

  decode(token: string): any {
    return jwt.decode(token);
  }
}

JwtMiddleware 구현

JWT 미들웨어는 다음과 같은 역할을 수행합니다:
1. 요청 헤더에서 JWT 토큰을 추출합니다.
2. 토큰을 JwtService.verify() 메서드를 사용하여 검증하고 페이로드를 반환합니다.
3. 반환된 페이로드를 이용해 사용자를 찾습니다.
4. 찾은 사용자의 정보를 요청 객체에 저장하여 다음 미들웨어 또는 컨트롤러에서 사용할 수 있도록 합니다.

import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { JwtService } from './jwt.service';
import { UsersService } from './users.service';

@Injectable()
export class JwtMiddleware implements NestMiddleware {
  constructor(
    private readonly jwtService: JwtService,
    private readonly usersService: UsersService
  ) {}

  async use(req: Request, res: Response, next: NextFunction) {
    if ('x-jwt' in req.headers) {
      const token = req.headers['x-jwt'].toString();
      try {
        const decoded = this.jwtService.verify(token);
        if (typeof decoded === 'object' && decoded.hasOwnProperty('id')) {
          const { user, ok } = await this.usersService.findById(decoded['id']);
          if (ok) {
            req['user'] = user;
          }
        }
      } catch (error) {
        // 토큰 검증 실패시 로그 처리 (필요에 따라 에러 처리)
        console.error('JWT verification failed:', error.message);
      }
    }
    next();
  }
}

사용자 서비스 예시

UsersService는 실제로 데이터베이스에서 사용자를 조회하고 성공 여부를 반환합니다. 다음은 UsersService의 예시입니다.

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';

@Injectable() // 이 클래스가 서비스로서 NestJS에 의해 인스턴스화되고 관리될 수 있음을 나타냄
export class UsersService {
    constructor(
        @InjectRepository(User) private readonly users: Repository<User>,
        private readonly jwtService: JwtService,
    ) { }
  
      async login({ email, password }: LoginInput): Promise<LoginOutput> {
        try {
           
            const token = this.jwtService.sign(user.id);
            return {
                ok: true,
                token,
            };

        } catch (error) {
            return {
                ok: false,
                error: "사용자가 로그인할 수 없습니다."
            }
        }
    }
}

마치며

NestJS에서 미들웨어를 통해 JWT 인증을 구현하면 각 요청에서 반복적으로 토큰을 검증하고 사용자 정보를 가져오는 과정을 간편하게 처리할 수 있습니다. 이로써 애플리케이션 전반에 걸쳐 안전하고 일관된 인증 메커니즘을 제공할 수 있습니다.

참고 자료

0개의 댓글