[uber-eats] user authentication - 3

한재창·2023년 6월 1일
0
post-thumbnail

Middleware

미들웨어를 설정하고 사용하는 이유는 token의 정보를 받고 사용자가 누군지 판별하기 위해서입니다.

미들웨어는 라우트 핸들러 전에 호출되는 함수입니다. 미들웨어 함수는 request 및 response 객체에 접근할 수 있으며 애플리케이션의 request-response 주기에 있는 next() 함수에 접근할 수 있습니다.
Nest 미들웨어는 기본적으로 익스프레스 미들웨어와 동일합니다. 함수 또는 @Injectable() 데코레이터가 있는 클래스에서 사용자 지정 Nest 미들웨어를 구현합니다.

Applying middleware 1 (미들웨어 적용 1)
@Module() 데코레이터에는 미들웨어가 들어갈 자리가 없습니다. 대신 모듈 클래스의 configure() 메서드를 사용하여 설정합니다. 미들웨어를 포함하는 모듈은 NestModule 인터페이스를 implement해야 합니다.

Middleware consumer
MiddlewareConsumer는 도우미 클래스입니다. 미들웨어를 관리하는 몇 가지 기본 제공 방법을 제공합니다. forRoutes() 메서드는 단일 문자열, 여러 문자열, RouteInfo 객체, 컨트롤러 클래스 및 여러 컨트롤러 클래스를 사용할 수 있습니다. 대부분의 경우 쉼표로 구분된 컨트롤러 목록을 전달할 것입니다.

apply()
apply() 메서드는 단일 미들웨어를 사용하거나 여러 인수를 사용하여 여러 미들웨어를 지정할 수 있습니다.

exclude()
지정한 경로에서 미들웨어의 실행을 제외합니다.

forRoutes()
전달된 경로 또는 컨트롤러에서 미들웨어를 실행합니다. 클래스를 전달하면 Nest는 이 컨트롤러 내에 정의된 모든 경로에 미들웨어를 실행합니다.

// app.module.ts

export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(jwtMiddleware).forRoutes({
      path: '/graphql',
      method: RequestMethod.POST,
    });
  }
}

Applying middleware 2 (미들웨어 적용 2)
미들웨어가 함수일 때만 사용할 수 있는 방법입니다. main.ts 파일의 bootstrap() 함수에서 app.use(jwtMiddleware); 를 입력해서 전역적으로 사용할 수 있다. 특정경로에서만 사용하고 싶다면 미들웨어 적용 1을 해야한다.

// main.ts

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  app.use(jwtMiddleware);
  await app.listen(3000);
}
bootstrap();

Context

각 request에 대해 request context를 사용할 수 있습니다. context가 함수로 정의되면 각 request마다 호출되고 req 속성에 request 객체를 받습니다.

Middleware 적용 방법

  1. [jwt] > jwt.middleware.ts 파일을 생성한 후, Middleware class 혹은 함수를 생성합니다.
    Middleware class는 NestMiddleware를 상속받아야 하는데 Injection 등의 NestMiddleware에서 상속되는 기능을 사용하지 않는다면 간단하게 함수로 생성합니다.

2-1. app.module.ts 파일의 AppModule class에서 NestModule를 상속합니다. NestModule는 configure() 메서드를 필요로 하기 때문에 호출한 뒤 consumer을 사용해 원하는 곳에 apply 할 수 있습니다.

2-2. 미들웨어가 함수일 때만 사용할 수 있는 방법입니다. main.ts 파일의 bootstrap() 함수에서 app.use() 메서드를 사용합니다. 전역적으로 사용할 때 쉽게 적용할 수 있습니다.

Middleware로 user 찾기

  1. 'localhost:3000/graphql'사이트 HTTP Headers 에서 { 'x-jwt' : Signature } 를 넘겨줍니다.

  2. jwt.service.ts 파일에서 verify() 메서드를 만들어서 토큰을 검증하고 페이로드를 반환할 수 있게 합니다.

  3. users.serivce.ts 파일에서 id로 user 정보를 찾을 수 있는 findById() 메서드를 만듭니다.

  4. jwt.middleware.ts 파일의 미들웨어에서 jwtService와 usersService를 사용할 수 있도록 constructor()에 설정해줍니다.

  5. 미들웨어의 use() 메서드에서 요청값의 headersdp 'x-jwt'가 존재한다면 token은 그 값이고 jwt.service.ts 파일의 verify() 메서드에 토큰 값을 넘겨서 토큰을 검증한 뒤 payload된 값(여기서는 'id')을 변수에 저장합니다.

  6. 해독된 값의 타입이 object이고 'id'라면 에러가 없을 때 users.serivce.ts 파일의 findById() 메서드의 인자로 decoded의 'id' 값을 넘겨 user의 정보를 찾아 리퀘스트에 'user' : user(user의 정보) 형식으로 저장합니다.

  7. graphql로 request를 공유하도록 app.module.ts 파일에서 context를 설정합니다. request는 context 안으로 들어오게 되는데 매 request가 마다 context가 호출되기 때문입니다.

전체 흐름

token을 보냄 > token은 request로 보내짐 > 그 request는 app.module.ts의 AppModule class의 configure() 메서드에서 잠시 멈춤 > JwtMiddleware가 먼저 토큰을 받아 미들웨어에서 토큰을 찾고 그것을 request user에 넣어줌 > request가 GraphQLModule로 와서 context 안으로 들어가게 됨

profile
취준 개발자

0개의 댓글