[Nest] Jwt와 Passport

mj·2021년 12월 29일
0

Nest에서의 jwt와 passport

What is Passport?

$ npm install --save @nestjs/passport passport passport-local
$ npm install --save-dev @types/passport-local

Passport는 Node.js의 미들웨어로 인증을 구현하게 할 수 있는 라이브러리입니다.

// src/auth/local.strategy.ts
import { Strategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { AuthService } from './auth.service';

@Injectable()
export class LocalStrategy extends PassportStrategy(Strategy) {
	constructor(private authService: AuthService) {
		super();
	}

	async validate(username: string, password: string): Promise<any> {
		const user = await this.authService.validateUser(username, password);
		if (!user) {
			throw new UnauthorizedException();
		}
		return user;
	}
}

passport는 여러 strategy(전략)이 있고 그 중에서 localstrategy는 local db와 user 정보를 가지고 인증을 하는 전략입니다.
LocalStrategy를 작성하기 위해 PassportStrategy 클래스를 상속받고 validate 함수를 오버라이드해 작성합니다.

@UseGuards

@UseGuards() 데코레이터는 CanActivate 인터페이스를 구현하고 @Injectable() 데코레이터를 달고 있는 클래스를 인자로 받아 클라이언트의 Request 요청을 검토합니다.

// app.controller.ts
import { Controller, Request, Post, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Controller()
export class AppController {
  @UseGuards(AuthGuard('local'))
  @Post('auth/login')
  async login(@Request() req) {
    return req.user;
  }
}

@UseGuards 데코레이터 안에 전략을 넣으면 자동으로 프로비저닝하여 컨트롤러나 핸들러 단위에서 라우트마다 요청을 검토하게 됩니다.

간단하게 생각하자!

로그인을 구현하기 위한 순서는 다음과 같다.
1. 로그인 api로 body에 email과 password가 담겨서 온다. (login service)
2. 로그인 api는 jwt를 통해 입력된 password가 secret으로 암호화된 비밀번호와 일치하면 토큰을 발급해준다. (토큰은 Header, payload, verify signature가 담겨 있다. 또한, payload에는 중요한 정보는 담아서 안되고 탈취당하면 공격자가 사용자 행세를 할 수 있으므로 refresh token 사용을 권장한다.)
3. 클라이언트는 발급받은 access token을 저장한다.
4. 클라이언트는 access token을 포함하여 권한이 필요한 api에 동봉하여 전달한다.
5. 서버는 access token의 payload를 passport의 validate 함수를 통해 검사하고 올바르다면 api의 request에 반환한다.
6. api는 받은 request를 통해 로직을 처리하고 다시 클라이언트에 응답한다.

글로 쓰니까 간단하지 않은 것 같다.
다시 정리하면
로그인하기 -> 검사하기 -> 토큰주기 -> 토큰저장하기 -> 토큰으로 요청하기 -> 토큰검사하기 -> 응답하기
로 요약할 수 있을 것 같다.

추가로..

access token은 탈취당하면 안되기 때문에 기간을 짧게 설정한다.
그러면 클라이언트에서는 다시 로그인해야 하는 불편함을 느끼게 된다.
또한 access token은 클라이언트에 저장하기 때문에 보안에 취약하다. 통신 중 access token을 탈취당할 수 있다.
그래서 refresh token이라는 것을 사용하는데 refresh token은 서버에 저장한다. 그리고 유효 기간을 길게 설정한다. ( 2주정도 )
access token으로 신나게 요청하다가 만료가 되면 만료된 token을 서버에 보내서 refresh token이 유효하다면 새 토큰을 발급해준다.
위와 같은 방법을 이용한다면 access token을 유효 기간을 짧게 잡아도 로그인을 다시 해야 하는 번거로움을 덜어낼 수 있고 서버에 저장된 refresh token을 탈취당할 걱정도 없앨 수 있습니다.

passport를 이용하면 token의 payload를 검사하여 인증할 수 있다는 것이 미들웨어를 통해 코드를 분리하고 nest process를 통해 request보다 먼저 실행된다는 점이 좋은 것 같다.

0개의 댓글