본문 바로가기

개발새발 개발자/JavaScript

[NestJs] Authentication 도전기 - 1 (feat.초보에겐 너무나 어려운 공식 문서)

프로젝트로 Nest.JS를 사용하게 되었다. Node.JS로 서버 구축 시 사용하는 프레임워크인 것 같은데, 타입 스크립트를 지원한다. 나는 타입 스크립트는 커녕 자바 스크립트도 1도 모르고 주먹구구 식으로 개미 눈꼽만큼만 써봤었기에 헤매는 일이 많았다.

 

일단 Nest의 공식 홈페이지 문서를 참고해 JWT를 구현하라는 미션을 받았다. JWT가 뭔지도 이번에 처음 안 나새끼...리스펙....

 

JWT를 알고 싶다면 아래의 링크로!

https://velopert.com/2389

 

[JWT] JSON Web Token 소개 및 구조 | VELOPERT.LOG

지난 포스트에서는 토큰 기반 인증 시스템의 기본적인 개념에 대하여 알아보았습니다. 이 포스트를 읽기 전에, 토큰 기반 인증 시스템에 대해서 잘 모르시는 분들은 지난 포스트를 꼭 읽어주세요. 이번 포스트에서는, 토큰 기반 인증 시스템의 구현체인 JWT (JSON Web Token) 에 대한 소개를 하고, JWT 토큰의 기본 구조를 알아보도록 하겠습니다. JSON Web Token 이 뭘까? 기본 정보 JSON Web Token (JWT) 은 웹표준 (RFC

velopert.com

 

실제 진행한 것은 아래와 같다.

https://docs.nestjs.com/techniques/authentication

 

Documentation | NestJS - A progressive Node.js web framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

이 글은 위의 부분을 진행하다 만난 이슈를 해결하는 험난했던 과정을 설명한다.

 

나는 어떤 언어나 프레임워크를 막론하고 공식 문서를 정말 싫어한다. 도대체 무슨 말인지 왕초보 입장에서는 이해하기가 힘들기 때문이다. 해석은 되는데 이해가 안된다.

 

차근 차근 '여기서는 이 파일을 만들고 이렇게 먼저 만들어놓으세요' 라고 설명해주지 않고 무턱대고 '니네 요런건 걍 알지? 생략한다?' 하고 끝나버린다.

 

예를 들면 이런거다.

 

아니 갑자기 저 users.service 파일은 어디서 나온건데요...저 파일은 무슨 내용이 있는 건데요...이거에 대한 설명이 1도 없이 자기 혼자 auth 기능을 설명하고 휙휙 지나가버린다.

 

내가 직접 만들어야 되는건지, 놓친건지 구분도 안 가고 왕초보는 혼란에 빠진다. 전체적인 폴더 구조라도 알려주면 따라서 만들어볼텐데...그게 그렇게 힘드냐! 흑흑

 

팀원에게 물어보니 일단 저 파일이 있다고 가정하고 설명하는 것 같다고 해서, 내가 임의로 users를 만들었다. 

 

사실 controller는 user가 필요한지 auth가 필요한지 모르겠어서 일단 만들고 봤다(...) 왜냐면,

 

공식 문서는 또 다시 불친절하게 이게 어디 컨트롤러인지 설명해주지 않았기 때문이다 ^_ㅜ 

 

확실히 알고 싶어서 일단 users.controller에 위의 내용을 넣고, auth.controller를 지워봤더니 정상 동작했다. 구현을 어떻게 할거냐에 따라 마음대로 정할 수 있는 것 같긴 한데, 저같은 초보는 그런 판단도 안 선다구요...! 그냥 그대로 따라하게 해주세요, 제발...! ㅠㅠ

 

일단 어찌저찌 해서 Bearer strategy 챕터를 완성하고 실행해보았는데,

 

에러가 생겼다. 아니 난 분명 홈페이지에 있는 코드 그대로 똑같이 따라했는데! 대체 뭐가 문젠데! 하며 분노의 눈빛으로 코드를 다시 일일이 살펴보지만....공식 문서와 다른 부분이 하나도 없었다. 답답했다. 구글링을 해도 나랑 코드가 같지 않기 때문에 적용하기가 힘들었다.

 

일단 빨간 글씨를 계속 읽었다. 해석은 되는데 무슨 소린지 이해가 안 간다. 무턱대고 일단 건드려봤다.

 

  1. auth.module에서 auth.service 파일을 못 받아오는 것 같다고 판단.
  2. 내가 만든 auth.module과 공식 문서의 auth.module을 비교 → 문제 없음.
  3. 하다보니 대체 module 파일은 이렇게 많은데 뭘 import 하고 export하고 어따가 쓰는 건지 도대체 이해가 안 가서 고구마 먹은 듯이 답답한 느낌 시작.
  4. module 부분 공식 문서를 조져보기로 결심.

https://docs.nestjs.com/modules

 

Documentation | NestJS - A progressive Node.js web framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

모듈이란 하나의 조각과 같은 거니까, 같은 주제를 담고 있는 쪼무래기 모듈은 그 대장 모듈에 합치고, 그럼 그 위에 있는 최종 보스 모듈은 대장 모듈만 넣어주면, 아래에 있던 쪼무래기 모듈들도 사용할 수 있다! 뭐 이런 개념인 것으로.

 

따라서, a와 b가 있으면

 

  • a.module에는 a.service와 a.controller가 들어간다.
  • b.module에는 b.service와 b.contoller가 들어간다.
  • a가 b.service를 사용하고 싶으면 a.module에 b.module만 import 하면 b.service를 사용할 수 있다.
  • 이때, b.module에서 a가 사용할 수 있도록 exports: [bService]를 해준다.

자, 그럼 여기서 내가 뭘 실수했는지 알 수 있다. 나는 auth에서 usersService를 사용하려고 했다. 그럼 auth.module에서 usersModule을 import 하는 것 뿐만 아니라, user.module에서도 usersService를 export 해줘야 하는 것이다!

 

- auth.module.ts

import { Module } from '@nestjs/common';
import { UsersModule } from '../users/users.module';
import { AuthService } from './auth.service';
import { HttpStrategy } from './http.strategy';

@Module({
    // In order to make use of UsersService, the AuthModule imports UsersModule.
    imports: [UsersModule],
    providers: [AuthService, HttpStrategy],
})
export class AuthModule {}

 

- users.module.ts

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { PassportModule } from '@nestjs/passport';

@Module({
  providers: [UsersService],
  controllers: [UsersController],
  
  // 이 부분을 추가해줬다.
  exports: [UsersService],
})
export class UsersModule {}

 

위와 같이 코드를 수정하고 다시 서버를 실행했다.

 

이제 앞에서 발생했던 에러는 처리가 되었다! 하지만 또 다른 에러의 시작^^ㅎ

 

defaultStrategy를 쓰려면 AuthGuard()가 사용되는 곳에 PassportModule을 넣어라...음...그걸 어떻게 하면 되죠????? 다시 초보의 수난기가 시작되었다.

 

앞에서 module에 넣으니 해결됐던 경험을 토대로 users.module과 auth.module에 아래와 같이 import를 해봤다.

import { Module } from '@nestjs/common';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { PassportModule } from '@nestjs/passport';

@Module({
  // 이렇게 users.module과 auth.module에 import를 해봤다.
  imports: [PassportModule],
  
  providers: [UsersService],
  controllers: [UsersController],
  exports: [UsersService],
})
export class UsersModule {}

하지만...장렬히 실패!

 

음...AuthGuard()를 다시 살펴볼까? 해서 users.controller를 들어가봤다.

import { Controller, Get, Injectable, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
@Controller()
export class UsersController {
    @Get('users')
    @UseGuards(AuthGuard())
    findAll() {
        return [];
    }
}

 

설마 AuthGuard의 괄호 안에 뭔가가 들어가야 하는 걸까? 라는 생각이 번뜩 들었다. (이 생각이 들기까지 삽질만 하다가 반나절을 훌쩍 넘겼다...왕초보는 이슈의 원인을 파악하는 것 마저도 너무나 긴 시간이 든다.)

 

아앗....공식 문서에는 'bearer'가 들어가있다...! 이걸 왜 놓쳤지. 바보바보 ㅠㅠㅠㅠ

 

다시 서버를 작동시키니 정상 실행 되었다!!!!

 

respond도 공식 문서가 계획한대로 401 에러를 찍었다!!!!!!! 야호!!!!!!!!

 

다른 사람들 같았으면 쉽게 풀었을 것 같은 문제를 이렇게 아침부터 하루종일 매달려 있었더니 뿌듯하긴 한데 진이 빠진다. 그래도 module 개념에 대해 어렴풋이 알게 되어 좋다!