본문 바로가기

Backend/NestJS

[NestJS]JWT(2) Guards, Passport에 대한 이해

728x90
 JWT에 대해 처음 공부하던 중
몇 가지 이해가 가지 않고 궁금한 개념들이 있었다.
이에 대한 공부 기록이다.

 

 

[NestJS] JWT(1) 기본 개념, 구현

JWT를 이용한 토큰 생성에 대한 공부 기록이다. JWT JWT(JSON Web Token) 당사자 간에 정보를 JSON 개체로 안전하게 전송하기 위한 컴팩트하고 독립적인 방식을 정의하는 개방형 표준으로 디지털 서명이

choi-records.tistory.com

개요

내가 궁금했던 것들은 아래와 같다.

  • Guards란?
  • Passport란?
  • Passport 모듈의 역할과 @nest/passport가 하는 역할
  • 배운 개념들이 어떻게 유기적으로 연결되는지

JWT에 대해 처음 배우고 기록할 때

어느 정도 이해가 됐지만 어떻게 유기적으로 동작하는지에 대한 궁금증이 남아있다.

 

각 코드의 의도를 명확히 파악하고,

위의 궁금증을 해결할 수 있도록 공부하며 기록할 예정이다.

Guards

https://docs.nestjs.com/guards

공식문서에서는 Guards의 역할이 클라이언트의 요청에 대한 권한 부여라고 한다.

Guards는 ExecutionContext 인스턴스에 액세스 할 수 있어 각 핸들러에 대해 권한 부여를 할지 판단할 수 있다.

때문에 Guards가 JWT를 이용한 인증 기능을 구현하는데 적합한 것이다.

 

파이프와 필터와 같이 Guards는 컨트롤러 범위, 메소드 범위, 글로벌 범위로 사용될 수 있다.

CanActive

CanActive 인터페이스는 Guards가 반드시 implements해야 한다.

CanActive 인터페이스에서 가장 중요한 것은

Guards가 지정한 범위 내에서의 요청에 대해 권한 부여를 할 것인지에 대한 판단을 반환해야 한다는 것이다.

 

정리해보면, Guards는 요청에 대한 권한 부여 역할을 하고,

CanActive 인터페이스를 implements 하는데 해당 인터페이스에서는

반드시 권한 부여에 대한 판단값을 반환하는 메소드를 가져야 한다.

Guards는 모든 middleware가 처리되고 파이프와 인터셉터가 실행하기 이전에 실행된다.

Passport

passport는 잘 알려진 인기 있는 node.js 인증 라이브러리이다.

passport의 도움은 아래와 같다.

  • 자격 증명(JWT, 자격 증명 토큰 등)을 확인하여 사용자를 인증
  • 인증 상태 관리(JWT나 세션 등을 생성)
  • 라우트 핸들러가 사용할 수 있도록 인증된 사용자에 대한 정보를 요청 객체에 첨부

passport는 다양한 인증 메커니즘을 구현하는 strategy 생태계가 있다.

이러한 다양한 메커니즘을 표준 패턴으로 추상화한 라이브러리이다.

 

@nest/passport 모듈은 이 패턴을 Nest 구조로 래핑하고 표준화한 것이다.

AuthGuard()

AuthGuards는 @nest/passport 모듈에서 제공하는 메소드이다.

export declare const AuthGuard: (type?: string | string[]) => Type<IAuthGuard>;

optional 한 타입을 받고 IAuthGuard타입의 데이터를 반환하는데

IAuthGuard는 

export declare type IAuthGuard = CanActivate & {

위에서 봤던 권한 판단값을 반환하는 CanActivate를 포함한다.

 

내용을 정리해 보면,

passport는 토큰을 생성하고, 생성한 토큰으로 사용자를 인증한다.

passport를 NestJS에서 원활하게 사용할 수 있게 해주는 @nest/passport 모듈은 AuthGuard라는 메소드를 제공한다.

AuthGuard는 핸들러 사용 권한에 대한 판단값을 가지는 CanActive를 포함한 데이터를 반환한다.

 

AuthGuard에서 반환한 값을 useGuard로 전달하고,

useGuard에서 전달받은 Guard를 통해 지정 범위에 대해 인증을 구현한다.

 

Strategy

passport는 JWT, local 등의 많은 strategy를 지원한다.

이 strategy string을 AuthGuard 메소드의 인자로 전달한다.

 

AuthGuard는 인증에 대한 판단값을 반환해야 하기 때문에

strategy 클래스는 validate() 메소드를 가지고 있어야 하는데 이 메소드에서 인증 기능을 수행한다.

 

jwt strategy 파일을 생성해 보자.

import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { InjectRepository } from '@nestjs/typeorm';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { IPayload } from './type/PayloadType';
import { User } from './user.entity';
import { UserRepository } from './user.repository';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(
    @InjectRepository(UserRepository)
    private userRepository: UserRepository, 
    ) {
    super({
      secretOrKey: 'Secret1234',
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
    });
  }
  async validate(payload: IPayload) {
    const { userName } = payload;
    const user: User = await this.userRepository.findOneBy({ userName });

    if (!user) {
      throw new UnauthorizedException();
    }

    return user;
  }
}

strategy 클래스는 PassportStrategy 클래스를 반드시 상속하며

필수로 지정해줘야 하는 값들을 super()를 통해 지정해 준다.

이 값에는 jwt 토큰 생성 시 사용하는 secret text값과 토큰의 타입이 있다.

 

위에서 언급한 대로 validate 메소드도 구현했다.

 

유기적 관계

먼저 auth module을 보자.

import { Module } from '@nestjs/common';
import { JwtModule } from '@nestjs/jwt';
import { TypeOrmExModule } from 'src/typeorm-ex.module';
import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
import { UserRepository } from './user.repository';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';

@Module({
  imports: [
    PassportModule.register({
      defaultStrategy: 'jwt',
    }),
    JwtModule.register({
      secret: 'Secret1234',
      signOptions: {
        expiresIn: 3600,
      },
    }),
    TypeOrmExModule.forCustomRepository([UserRepository]),
  ],
  controllers: [AuthController],
  providers: [AuthService, JwtStrategy],
  exports: [JwtStrategy, PassportModule],
})
export class AuthModule {}

passport module에서 strategy를 jwt로 기본 설정한 모듈과

JWT module에서 secret text와 유효 시간을 지정한 모듈을 가져왔다.

JWT module은 JWT service를 지원하는데 여기서 로그인 시 해당 정보를 payload로 갖는 토큰을 생성할 수 있다.

 

JWT strategy를 provider로 지정함으로써

passport의 기능을 JWT strategy로 사용할 수 있도록 했다.

 

JWT strategy와 passport module을 export 해서 다른 모듈에서도

JWT startegy에 의한 passport의 인증 기능을 구현할 수 있도록 했다.

 

정리하면 JWT는 provider를 통해 로그인 시 해당 정보를 담는 토큰을 반환,

passport는 JWT strategy 파일로부터 JWT 토큰 생성 시 이용한 secret text와 토큰 형식을 받아서

요청 헤더의 토큰이 유효한지 판단하고 그 판단값을 useGuards로 반환하는 역할을 한다.


참고

 

Documentation | NestJS - A progressive Node.js 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

 

Documentation | NestJS - A progressive Node.js 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

https://www.youtube.com/watch?v=3JminDpCJNE&t=19151s 

마치며

잘못된 정보에 대한 피드백은 환영입니다.

감사합니다.

 

 

728x90