[Typescript] Nest.js


(Typescript) Nest.js JWT 인증 모듈 개발자

소개

이번 포스팅에서는 Nest.js에서 JWT 인증 모듈을 개발한 경험을 가지고 왔습니다.

사실 JWT 인증 모듈을 만들 때 개인적으로 고려했던 부분들이 포함되어 있습니다.

1. 프로젝트 구조

JWT 인증/발급 기능의 이익을 분리하고 “JWT 인증 모듈”만 갖기 위해 다음과 같은 프로젝트 구조를 가졌습니다.

  • global.d.ts: JWT를 전역적으로 사용하기 위해 이 파일에 전역 인터페이스를 정의합니다.

  • jwt-auth.module.ts: PassportModule 또는 JwtModule을 import하여 초기화하기 위한 파일입니다.

    이 모듈에는 @Global() 데코레이터가 붙어 있기 때문에 jwt 인증/발급 기능을 사용하는 다른 모듈로 jwt-auth.module을 가져오지 않고 jwt-auth.service만 공급자로 등록하고 사용할 수 있습니다.

  • jwt-auth.service.ts: JWT 인증 및 발급을 처리하는 서비스(@Injectable() 클래스)입니다.

    jwt-auth.module을 통해 내보내고 다른 모듈에서는 이 jwt-auth.service만 공급자로 등록하여 JWT 인증/발급/파싱 기능을 사용할 수 있습니다.

  • jwt-auth.strategy.ts: 이 파일은 클라이언트로부터 요청을 받았을 때 헤더나 쿠키에 포함된 JWT를 인증하기 위한 정책(메서드)을 정의합니다.

    이 파일에서는 사용자가 유효한 사용자인 경우 데이터베이스의 사용자 쿼리 및 인증 통과와 같은 작업만 수행할 수 있습니다.

  • jwt-auth.guard.ts: @nestjs/passport에서 AuthGuard를 상속받은 인증 필터로 @UseGuards() 데코레이터를 통해 실제 컨트롤러 함수에 부착하여 사용할 수 있습니다.

    이 파일에 정의된 가드를 @UseGuards() 데코레이터의 매개변수로 전달하여 컨트롤러에 연결하면 jwt-auth.strategy에 정의된 정책에 따라 인증이 수행됩니다.

    그리고 이 파일은 AuthGuard의 canActive() 재정의 기능을 구현하여 헤더 또는 쿠키의 JWT 문자열을 구문 분석하고 요청 객체에 속성으로 저장합니다.

    그런 다음 이 속성은 아래에서 설명하는 jwt.decorator에서 사용됩니다.

  • jwt.decorator.ts: 이것은 @nestjs/comons createParamDecorator() 로 생성된 JWT 캡처 매개변수 데코레이터입니다.

    이 데코레이터는 요청 개체 속성에 저장된 구문 분석된 JWT 개체를 매개 변수로 사용하는 함수를 구현합니다.

위의 구조로 이 모듈은 JWT 관련 기능에 대한 관심에 전념합니다.

그리고 @Global() 모듈을 사용하면 가드와 데코레이터가 이 모듈을 사용하는 다른 모듈에서 생성되는 상용구를 줄일 수 있습니다.

이렇게 하면 테스트 및 리팩토링이 쉬워집니다.

2. 모듈 구현

2-1 global.d.ts

전역적으로 JWT 인터페이스를 사용하도록 정의됩니다.

JWT 페이로드에 포함될 인터페이스 구조는 필요에 따라 사용자 정의하여 사용할 수 있습니다.

2-2 jwt-auth.module.ts

이 파일은 JWT 모듈을 정의합니다.

다른 모듈이 jwt-auth.module을 가져오지 않고 jwt-auth.module에서 내보낸 클래스를 사용할 수 있도록 전역적으로 @Global() 데코레이터를 추가합니다.

@nestjs/passport의 PassportModule과 @nestjs/jwt의 JwtModule을 이 파일로 가져옵니다.

이 시점에서 환경 변수를 사용하여 JwtModule 비밀을 초기화하기 위해 ConfigModule 서비스가 비동기식으로 삽입 및 처리됩니다.

그리고 jwt-auth.strategy.ts 및 jwt-auth.service.ts를 provider로 등록하고 jwt-auth.service.ts를 export로 등록하여 다른 모듈에서 사용할 수 있도록 합니다.

이때 주목해야 할 점 @nestjs/jwt JWT 인증/발급/파싱 기능을 정상적으로 사용하기 위해서는 JwtService도 Provider로 등록하고, 내보내기에 JwtModule도 등록해야 합니다.

2-3 jwt-auth.service.ts

이 파일은 JWT 인증/발급/파싱 기능을 사용자 지정하기 위한 서비스를 정의합니다.

@nestjs/jwt의 JwtService를 직접 사용하는 경우 전역적으로 정의된 JwtPayload를 매번 제네릭으로 주입해야 하므로 JwtAuthService라는 별도의 서비스를 생성하여 정의하였다.

의도는 JwtService의 기능을 패키징하는 것이었지만 요청 객체의 헤더 또는 쿠키 속성에서 JWT 문자열을 추출하는 함수 또는 추출된 JWT 문자열을 구문 분석하여 객체로 반환하는 함수를 정의하는 것이었습니다.

2-4 jwt-auth.strategy.ts

이 파일은 JWT 인증을 위한 JWT 추출 위치 및 암호와 인증 논리를 정의합니다.

인증 헤더와 jwt 쿠키는 모두 추출하도록 정의되어 있으며 사용자 인증은 validate() 함수 정의를 통해 처리됩니다.

validation() 함수에 DB select와 같은 과정을 넣어주면 유효한 사용자만 인증을 통과할 수 있습니다.

2-5 jwt-auth.guard.ts

@UseGuards() 데코레이터를 사용하여 다른 모듈의 컨트롤러 기능에 JWT 인증 필터를 붙이기 위한 파일입니다.

@nestjs/passport에서 AuthGuard를 상속하여 구현하고 AuthGuard의 canActivate() 함수를 재정의하여 파싱된 JWT 객체를 요청 객체에 주입하는 기능을 구현합니다.

jwtAuthService.getJwtAndVerifyFromReq() 함수는 요청 객체에서 JWT 문자열을 추출하고 구문 분석하여 객체로 반환합니다.

이것이 실패하면 예외가 발생합니다.

이 경우 인증에 실패했기 때문에 잡아서 UnauthorizedException을 던졌습니다.

2-6 jwt.decorator.ts

이 파일은 jwt-auth.guard를 통해 요청 객체 속성으로 삽입된 JWT 객체를 매개변수에 넣는 데코레이터를 정의합니다.

컨트롤러에 요청 객체에서 JWT를 추출하는 상용구를 매번 작성하면 유지보수가 어려워지므로 이 프로세스 데코레이터의 연결이 끊어집니다.

3. 사용

이 JwtAuthModule을 사용하려면 먼저 ConfigModule 및 JwtAuthModule을 app.module.ts로 가져와야 합니다.

그리고 JWT 기능을 사용하기 위해 JwtAuthModule 서비스를 모듈에 공급자로 등록하고 서비스 생성자로 가져옵니다.


컨트롤러에서 @UseGuards() 데코레이터를 사용하여 JwtAuthGuard를 컨트롤러 함수에 연결하고 JWT 개체를 검색해야 하는 경우 @Jwt() 데코레이터를 사용합니다.

이 시점에서 @Jwt() 데코레이터를 통해 JWT 개체를 가져오려면 JwtAuthGuard를 컨트롤러 함수에 연결해야 합니다.