-
[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에서는 어떻게 찾는 걸까?
@nestjs/passport 패키지의 PassortStrategy를 상속받아서 CustomJwtStrategy를 만들었습니다. 헤더의 BearerToken을 가져와서 디코딩한 뒤 validate 함수에서는 실제 user가 존재하는지 확인하는 과정입니다.
Nest.js를 공부한 지 얼마 안 됐지만 해당 모듈에서 CustomJwtStrategy를 사용하려면 providers에 주입해야 사용할 수 있다고 배웠고, 실제로 providers에 주입하지 않으면 사용이 불가합니다.
오 그래서! providers에 내가 새로 만든 Strategy를 주입하면 controller에서 사용이 가능하구나!라는 생각을 했습니다.
강의에서 @UseGuars(AuthGuard())를 사용하면 제가 만든 CustomJwtStrategy를 사용할 수 있다고 했고 Postman으로 동작할 때도 그렇게 동작이 되었습니다.
한 가지 의문점은
내가 Providers에 CustomJwtStrategy를 주입해줬지만
AuthGuard에서는 그걸 어떻게 찾는 걸까?라는 의문점과 함께(삽질과 함께) 디버깅을 찍어보았습니다.
처음에는 passport 깃헙에 가서 관련 로직이 있는지 찾아봤는데 보이지가 않더라고요.
🐛 디버깅 과정 및 설명
런타임 과정에서 passport 패키지 내부에서 여러 가지 일들이 일어납니다.
일단 위 이미지에서 보시다시피 Authenticator라는 함수가 init()을 실행합니다.
여기서 첫 번째 힌트를 얻을 수 있습니다.
init함수에서는 this.use()라는 함수로 SessionStrategy를 뭔가 사용한다(?)라는 로직을 실행했습니다.
좀 더 들어가 보면...
this._strategies라는 변수에 SessionStoragy가 추가되었습니다.
오! 뭔가 여기까지 보면 Authenicator의 use 함수를 통해 Strategy를 내부 변수에 넣는구나라는걸 알 수 있습니다.
계속 디버깅을 실행시켜 보면(StepIn) 제가 커스텀으로 만든 CustomJwtStrategy를 만나고 constructor의 super()가 실행이 됩니다. super()는 다들 아시다시피 부모 클래스의 함수를 실행시키는 거죠?
여기서는 PassportStrategy의 Constructor가 실행이 되겠네요. 그럼 한 번 더 StepIn으로 들어가 보겠습니다.
MixinStrategy constructor 내부 로직을 보면 validate 관련해서 callback을 정의하는 로직들이 있네요. 잘은 모르지만 느낌상으로는 controller에서 strategy의 validate를 호출해서 검증을 하는 로직 같아 보이네요.
좀 더 아래를 살펴보면 passportInstance를 받아와서 use 함수를 사용하는 로직을 볼 수 있습니다. 어디서 많이 본 것 같지 않으신가요? 위에 Auathenticator의 use와 비슷하죠?
this는 우리가 정의한 CustomJwtStrategy이고, passportInstance는 Auathenticator 였습니다.
그리고 그다음은 처음 SessionStrategy가 주입된 것처럼 this._strategies에 주입이 됩니다.
Strategy name이 jwt 인 것은 CustomJwtStrategy를 구현할 때 passport-jwt 패키지의 strategy를 전략으로 넣어줬기 때문입니다.
그러면 이 strategy가 어떻게 되어있는지 한번 확인해보겠습니다.
여기 보시면 this.name에 jwt 인 것을 볼 수 있습니다. 그래서 default name이 jwt인 것입니다.
근데 왜 주입되는 건 Strategy인데 JwtStrategy이냐?
물으신다면 ㅎㅎ
표현이 잘 맞는지 모르겠지만(TypeScript 초짜라), 위 와 같은 식으로 Strategy를 가져오기 때문에 우리가 사용하는 진짜 전략은 JwtStrategy를 상속받아 사용하는 것입니다!
휴... 별 거 아니지만 긴 여정이었다.
💡 긴 여정의 끝에 결론
제가 개인적으로 헷갈렸던 부분은 nest.js에서 passport를 사용해서 Strategy를 주입하고 export 해주는 로직들이 라이브러리에 숨겨져 있어서 한 번에 이해가 안 갔던 것 같습니다.
강의에서도 그냥 providers에 Strategy를 주입하면 AuthGuard에서 알아서 찾아서 동작한다는 마법 같은 느낌을 받아서요.
실제로 마법은 존재하지 않고 일련의 과정들이 패키지 내에서 런타임 시 일어나고 있었습니다.
nest.js가 아니라 express에서 passport를 사용해서 jwt를 구현했다면은 위 과정을 좀 더 쉽게 이해했을 것 같습니다.
아래 블로그를 보시면 express에서 passport 사용한 걸 볼 수 있는데 위에서 우리가 디버깅으로 순차적으로 찾아왔던 로직들을 직접 구현하는 걸 보실 수 있습니다.
https://chanyeong.com/blog/post/28
👋 마치며
사실 당연하다고 생각할 수 도 있는 부분들인데 개인적으로 Node.js, TypeScript가 익숙하지 않은 상황에서 Nest.js 강의를 보고 따라 하다 보니 "이건 왜 이렇게 동작하지?" 등의 의구심이 많이 생겼던 것 같습니다.
그래도 덕분에 패키지들을 보면서 좀 더 TypeScript, Nest.js와 친숙해졌고 중간중간 제가 모르는 문법들은 찾아보면서 공부해야겠네요!
그럼 오늘도 좋은 하루 되시고 서버가 멀쩡하길 바래요~
'💻 프로그래밍 > node' 카테고리의 다른 글
[AWS Lambda] Nodejs 16.x 지원종료, 18.x 버전업 대응 요약(feat.s3) (1) 2023.10.04 [NestJS] 모든게 싱글톤 인스턴스 아니었어? (imports, providers 주의사항) (0) 2022.07.21 [Node.JS] Express 로 api 서버 만들기 (4) 2020.07.28