[NestJS] JWT 와 미들웨어

sm·2023년 7월 13일
1

udemy

목록 보기
7/12
post-thumbnail
post-custom-banner

https://docs.nestjs.com/middleware

미들웨어

미들웨어는 라우트 핸들러(route handler)가 호출되기 전에 실행되는 함수. 미들웨어 함수는 요청(request)과 응답(response) 객체, 그리고 애플리케이션의 요청-응답 주기(request-response cycle)에서 next 미들웨어 함수에 대한 접근 권한을 가지고 있다.

애플리케이션의 요청과 응답 처리를 중간에 가로채고 변경하거나 보완하는 데 사용한다. 이를 통해 코드 중복을 줄이고, 요청 처리에 필요한 공통 작업을 재사용할 수 있다. 또한, 미들웨어는 애플리케이션의 유연성과 확장성을 향상시키는 데에도 도움을 준다고 한다.


  • req(request): 요청 객체로서 클라이언트로부터 받은 요청에 대한 정보를 포함. 미들웨어 함수에서 요청에 대한 작업을 수행하거나 요청의 속성을 읽고 수정할 수 있다.
  • res(response): 응답 객체로서 클라이언트로 보낼 응답에 대한 정보를 포함. 미들웨어 함수에서 응답을 생성하거나 응답의 속성을 설정할 수 있다.
  • next(): 다음 미들웨어 함수를 호출하기 위한 함수. 현재 미들웨어 함수에서 작업을 완료하고 다음 미들웨어 함수로 제어를 전달할 때 사용된다. next()를 호출하지 않으면 미들웨어 체인이 중단되고 요청 처리가 중지될 수 있습니다.

app.module.ts

import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common';
import { AppController } from '@app/app.controller';
import { AppService } from '@app/app.service';
import { TagModule } from '@app/tag/tag.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import ormconfig from '@app/ormconfig';
import { UserModule } from '@app/user/user.module';
import { AuthMiddleware } from './user/middlewares/auth.middleware';

@Module({
  imports: [TypeOrmModule.forRoot(ormconfig), TagModule, UserModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {
  //global middleware
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(AuthMiddleware).forRoutes({
      path: '*',
      method: RequestMethod.ALL,
    });
  }
}

미들웨어를 사용하려면 configure 메서드를 AppModule에 정의해야 한다. configure 메서드는 Nest의 MiddlewareConsumer를 사용하여 미들웨어를 등록하고 설정하는 역할을 한다. apply 메서드를 사용하여 AuthMiddleware를 등록하고, forRoutes 메서드를 사용하여 어떤 경로와 HTTP 메서드에 대해 미들웨어를 적용할지 지정할 수 있다.

AuthMiddleware를 모든 경로(path: '*')와 모든 HTTP 메서드(method: RequestMethod.ALL)에 대해 등록하고 있다(전역 미들웨어). 애플리케이션의 모든 요청에 대해 인증 미들웨어를 적용하겠다는 의미!


middlewares/auth.middleware.ts

import { Injectable, NestMiddleware } from '@nestjs/common';
import { NextFunction, Response } from 'express';
import { ExpressRequest } from '@app/user/types/expressRequest.interface';
import { verify } from 'jsonwebtoken';
import { JWT_SECRET } from '@app/config';
import { UserServie } from '@app/user/user.service';

@Injectable()
export class AuthMiddleware implements NestMiddleware {
  constructor(private readonly userService: UserServie) {}

  async use(req: ExpressRequest, _: Response, next: NextFunction) {
    console.log('authMiddle', req.headers);

    if (!req.headers.authorization) {
      req.user = null;
      next();
      return;
    }

    const token = req.headers.authorization.split(' ')[1];


    try {
      const decode = verify(token, JWT_SECRET);
      const user = await this.userService.findById(decode.id);
      req.user = user;
      next();
    } catch (err) {
      req.user = null;
      next();
    }
  }
}

NestMiddleware는 Nest.js의 미들웨어 인터페이스.

AuthMiddleware 클래스는 NestMiddleware를 구현하고 있으므로, use 메서드를 구현해야 한다. use 메서드는 미들웨어의 핵심 로직을 포함(req, res, next)

req.headers.authorization을 확인하여 토큰이 있는지 확인한다. 토큰이 없으면 req.usernull로 설정하고 next()를 호출하여 다음 미들웨어로 넘어간다.

토큰이 있는 경우,req.headers.authorization을 공백으로 분리하여 토큰 부분만 추출. 그리고 jsonwebtoken 패키지의 verify 함수를 사용하여 토큰을 검증한다. 이때 JWT_SECRET을 사용하여 토큰을 해독한다.

토큰이 유효하면 this.userService.findById(decode.id)를 사용하여 사용자를 데이터베이스에서 찾고 토큰이 유효하지 않은 경우, req.usernull로 설정.


user.controller.ts

  @Get('user')
  async currentUser(
    @Req() request: ExpressRequest,
  ): Promise<UserResponseInterface> {
    console.log('current user in controller', request.user);
    return this.userService.buildUserResponse(request.user);
  }

currentUser 핸들러는 현재 로그인한 사용자의 정보를 반환하는 역할
미들웨어에서 토큰을 해독하고 사용자를 조회하여 request.user에 저장하면, 이후에 실행되는 컨트롤러에서 request.user를 활용할 수 있다.

미들웨어를 통해 토큰을 검증하고 사용자를 조회한 후, 컨트롤러에서 해당 정보를 활용하여 사용자의 응답을 구성. 이를 통해 중복된 로직을 줄이고 코드의 재사용성을 높일 수 있음.(미들웨어를 사용하여 토큰 검증과 사용자 조회를 한 번만 작성하면 되기 때문!)


흠..아직은 어렵다..

profile
📝 It's been waiting for you
post-custom-banner

0개의 댓글