ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [NestJS] AuthGuard는 어떻게 JwtStrategy를 찾는걸까? 마법인가? 🥳
    💻 프로그래밍/node 2022. 4. 7. 03:42

    안녕하세요! 개발자 Jay입니다.

    오늘은 Nest.js 스터디중 잘 이해가 안 되었던 것들에 대해 정리해보려고 합니다.

     

    일단 갑자기 Nest.js 스터디를 하게된 건 회사에서 사용하는 백엔드 애플리케이션 기술 스택이 Django, FastAPI, Nest.js 이렇게 크게 세 가지 정도를 사용하고 있기 때문에 가장 접근해보지 못한 Nest.js 스터디를 시작했습니다.

     

    스터디를 하면서 사내 서비스 피쳐(feature) 개발을 하는데 도움이 될 것 같기도 했고요! 

    여하튼 장장 6시간의 강의를 듣고 UseGaurds 데코레이터를 사용하여 권한을 JWT 토큰 인증하는 과정에서 의문점이 생겼습니다.

    providers에 주입된 커스텀 Strategy를 AuthGuard에서는 어떻게 찾는 걸까?

    PassportStrategy 를 상속받아 CustomJwtStrategy를 생성

    @nestjs/passport 패키지의 PassortStrategy를 상속받아서 CustomJwtStrategy를 만들었습니다. 헤더의 BearerToken을 가져와서 디코딩한 뒤 validate 함수에서는 실제 user가 존재하는지 확인하는 과정입니다.

     

    providers 에 주입된 CustomJwtStrategy

    Nest.js를 공부한 지 얼마 안 됐지만 해당 모듈에서 CustomJwtStrategy를 사용하려면 providers에 주입해야 사용할 수 있다고 배웠고, 실제로 providers에 주입하지 않으면 사용이 불가합니다.

     

    providers에 주입하지 않은경우 에러

    오 그래서! providers에 내가 새로 만든 Strategy를 주입하면 controller에서 사용이 가능하구나!라는 생각을 했습니다.

     

    controller에서 UseGuards 사용

    강의에서 @UseGuars(AuthGuard())를 사용하면 제가 만든 CustomJwtStrategy를 사용할 수 있다고 했고 Postman으로 동작할 때도 그렇게 동작이 되었습니다.

     

    한 가지 의문점은

    내가 Providers에 CustomJwtStrategy를 주입해줬지만
    AuthGuard에서는 그걸 어떻게 찾는 걸까?

     

    라는 의문점과 함께(삽질과 함께) 디버깅을 찍어보았습니다.

    처음에는 passport 깃헙에 가서 관련 로직이 있는지 찾아봤는데 보이지가 않더라고요.

     

    🐛  디버깅 과정 및 설명


    지금부터 긴 여정이 있을것입니다~ㅋㅋ

     

    passport 패키지 내부 Authenticator init 과정

    런타임 과정에서 passport 패키지 내부에서 여러 가지 일들이 일어납니다.

    일단 위 이미지에서 보시다시피 Authenticator라는 함수가 init()을 실행합니다.

    여기서 첫 번째 힌트를 얻을 수 있습니다.

     

    init함수에서는 this.use()라는 함수로 SessionStrategy를 뭔가 사용한다(?)라는 로직을 실행했습니다.

    좀 더 들어가 보면...

     

    SessionStrategy가 변수에 주입되었다

    this._strategies라는 변수에 SessionStoragy가 추가되었습니다.

    오! 뭔가 여기까지 보면 Authenicator의 use 함수를 통해 Strategy를 내부 변수에 넣는구나라는걸 알 수 있습니다.

     

    계속 디버깅을 실행시켜 보면(StepIn) 제가 커스텀으로 만든 CustomJwtStrategy를 만나고 constructorsuper()가 실행이 됩니다. super()는 다들 아시다시피 부모 클래스의 함수를 실행시키는 거죠?

     

    CustomJwtStrategy constructor를 실행

    여기서는 PassportStrategyConstructor가 실행이 되겠네요. 그럼 한 번 더 StepIn으로 들어가 보겠습니다.

    어디서 많이 본 형태이다

    MixinStrategy constructor 내부 로직을 보면 validate 관련해서 callback을 정의하는 로직들이 있네요. 잘은 모르지만 느낌상으로는 controller에서 strategy의 validate를 호출해서 검증을 하는 로직 같아 보이네요.

     

    좀 더 아래를 살펴보면 passportInstance를 받아와서 use 함수를 사용하는 로직을 볼 수 있습니다. 어디서 많이 본 것 같지 않으신가요? 위에 Auathenticator의 use와 비슷하죠?

     

    this, passportInstance 의 비밀

    this는 우리가 정의한 CustomJwtStrategy이고, passportInstance는 Auathenticator 였습니다. 

    this._strategies 에 주입

    그리고 그다음은 처음 SessionStrategy가 주입된 것처럼 this._strategies에 주입이 됩니다.

    Strategy name이 jwt 인 것은 CustomJwtStrategy를 구현할 때 passport-jwt 패키지의 strategy를 전략으로 넣어줬기 때문입니다.

    이 Strategy를 주입해줬기 때문!!

    그러면 이 strategy가 어떻게 되어있는지 한번 확인해보겠습니다.

    알고보니 JwtStrategy

    여기 보시면 this.name에 jwt 인 것을 볼 수 있습니다. 그래서 default name이 jwt인 것입니다.

    근데 왜 주입되는 건 Strategy인데 JwtStrategy이냐? 

    물으신다면 ㅎㅎ

    passport-jwt 의 Strategy 는 JwtStrategy를 requrie로 전달 받기 때문

    표현이 잘 맞는지 모르겠지만(TypeScript 초짜라), 위 와 같은 식으로 Strategy를 가져오기 때문에 우리가 사용하는 진짜 전략은 JwtStrategy를 상속받아 사용하는 것입니다!

     

    휴... 별 거 아니지만 긴 여정이었다.

     

    💡 긴 여정의 끝에 결론


    끝이당!

    제가 개인적으로 헷갈렸던 부분은 nest.js에서 passport를 사용해서 Strategy를 주입하고 export 해주는 로직들이 라이브러리에 숨겨져 있어서 한 번에 이해가 안 갔던 것 같습니다.

    마법은 존재하지 않는다

    강의에서도 그냥 providers에 Strategy를 주입하면 AuthGuard에서 알아서 찾아서 동작한다는 마법 같은 느낌을 받아서요.

    실제로 마법은 존재하지 않고 일련의 과정들이 패키지 내에서 런타임 시 일어나고 있었습니다.

     

    nest.js가 아니라 express에서 passport를 사용해서 jwt를 구현했다면은 위 과정을 좀 더 쉽게 이해했을 것 같습니다.

    아래 블로그를 보시면 express에서 passport 사용한 걸 볼 수 있는데 위에서 우리가 디버깅으로 순차적으로 찾아왔던 로직들을 직접 구현하는 걸 보실 수 있습니다.

    https://chanyeong.com/blog/post/28

     

    Passport.js + JWT 로 유저 인증 하기 :: chanyeong

    일단 passport와 jwt를 사용하기 전에 이 두가지가 무엇인지부터 알아보도록 하자. JWT란? JWT(JSON Web Token)은 클라이언트와 서버 혹은 서비스간의 통신시 정보를 JSON객체를 통해 안전하게 전송하고 권

    chanyeong.com

     

    👋 마치며


    사실 당연하다고 생각할 수 도 있는 부분들인데 개인적으로 Node.js, TypeScript가 익숙하지 않은 상황에서 Nest.js 강의를 보고 따라 하다 보니 "이건 왜 이렇게 동작하지?" 등의 의구심이 많이 생겼던 것 같습니다.

     

    그래도 덕분에 패키지들을 보면서 좀 더 TypeScript, Nest.js와 친숙해졌고 중간중간 제가 모르는 문법들은 찾아보면서 공부해야겠네요!

    그럼 오늘도 좋은 하루 되시고 서버가 멀쩡하길 바래요~

     

    서버신이시여~

    댓글

운동하는 개발자 JAY-JI