본문 바로가기

Backend/NestJS

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

728x90
JWT를 이용한 토큰 생성에 대한 공부 기록이다.

JWT

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

구조

Header

토큰에 대한 메타 데이터를 포함하고 있다.

ex) 타입, 해싱 알고리즘 등

 

Payload

사용자 권한 정보와 데이터를 포함하고 있다.

ex) 유저 정보, 만료 기간 등

Verify Signature

헤더와 페이로드는 단순하게 인코딩하기 때문에 공격자는 원하는 값을 넣고 토큰을 생성할 수 있다.

따라서 생성된 토큰이 유효한지 검증하는 장치가 필요하다.

 

토큰이 보낸 사람에 의해 서명되었으며, 어떤 식으로든 변경되지 않았는지 확인하는 데 사용되는 정보

헤더 및 페이로그 세그먼트, 서명 알고리즘, 비밀 또는 공개 키를 사용하여 생성된다.

위처럼 서버에서 secret text를 통해 인코딩한다는 것을 알 수 있다.

 

아래 페이지에서 인코딩 된 토큰을 통한 디코딩된 토큰을 얻을 수 있다.

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

사용 흐름

유저가 로그인하면 위의 정보를 해시 알고리즘을 통해 인코딩해 토큰을 생성한다.

생성한 토큰을 보관한다.

 

유저가 요청을 보냈다고 가정해 보자,

해당 요청은 권한이 필요한 응답이다.

따라서 요청 헤더의 토큰이 유효한지 확인한다.

 

서버에서 발급한 해당 유저의 토큰과 요청 헤더의 토큰이 일치하면 토큰이 유효하다고 판단한다.

 

인증 vs 인가
인증 : 유저나 디바이스의 신원을 증명하는 행위
ex) 신분증을 통해 본인임을 증명
인가 : 유저나 디바이스에게 접근 권한을 부여하거나 거부하는 행위
ex) 티켓을 통해 입장 권한이 있음을 증명

JWT 구현

필요 모듈 설치

$npm i -D @nestjs/jwt
- NestJS에서 jwt를 사용하기 위해 필요한 모듈
$npm i -D passport
- passport 모듈

Passport는 JWT를 이용한 인증 처리 과정을 쉽게 만들어주기 때문에 사용한다.

 

모듈 등록하기

auth 모듈에서 imports에 넣어준다.

@Module({
  imports: [
    JwtModule.register({
      secret: 'Secret1234',
      signOptions: {
        expiresIn: 3600,
      },
    }),
    TypeOrmExModule.forCustomRepository([UserRepository]),
  ],
  controllers: [AuthController],
  providers: [AuthService],
})
export class AuthModule {}
  • secret : 위에서 봤던 secret text를 지정해 준다.
  • expiresIn : 토큰의 유효 시간을 지정해 준다.

Service 파일에 JwtService 주입

  constructor(
    private jwtService: JwtService,
  ) {}

위와 같이 모듈에서 import 한 JwtModule이 동적으로 반환한 JwtService를 주입해 준다.

토큰을 생성하고 반환

  async signIn(authCredentialDto: AuthCredentialDto): Promise<IToken> {
    const { userName, password } = authCredentialDto;
    const user = await this.userRepository.findOneBy({ userName });
    
    if (user && (await bcrypt.compare(password, user.password))) {
      const payload = { userName };
      const accessToken = await this.jwtService.sign(payload);
      return { accessToken };
    } else {
      throw new UnauthorizedException('Login failed');
    }
  }

로그인 시 해당 유저의 이름을 담고 있는 토큰을 생성해서 반환한다.

토큰이 정상적으로 반환된 것을 볼 수 있다.

 

728x90