JWT를 구현해보자(1)
NestJS를 이용해 JWT를 구현해보자
서론
저번 게시글에서는 JWT에 대해서 알아보았다.
JWT를 NestJS를 통해 로그인 시스템을 만들고 JWT로 인증하는 프로젝트를 직접 구현해보자.
사용할 라이브러리
사용할 라이브러리는 아래와 같다.
1
npm install bcrypt @types/bcrypt
우선 단방향 암호화를 위한 라이브러리인 bcrypt를 설치해준다.
비밀번호 보안을 위한 암호화 알고리즘을 제공하는 라이브러리이다.
1
npm install @nestjs/jwt
nestjs에서 JWT를 구현해줄 라이브러리이다.
설정한 키값으로 인코딩을 진행해주고, 요청이 들어올경우 토큰을 검사하여 맞는 사용자를 인증해주는 라이브러리이다.
1
npm install mysql2 typeorm @nestjs/typeorm
TypeORM을 이용해 데이터베이스를 다룰 것이고, 사용할 데이터베이스는 mysql 이다.
1
npm install @nestjs/config
nestJS env를 이용해 환경변수를 사용하기위한 라이브러리이다.
1
npm install class-validator class-transformer
DTO를 사용하기 위한 라이브러리들이다.
1
npm install @nestjs/passport passport @types/passport-local passport-local
인증 프로세스를 처리하기위한 passport 라이브러리를 설치한다.
모듈 설정
우선 환경변수를 사용하기위해 ‘configuration.module.ts’ 라는 파일을 만들어준다.
1
2
3
4
5
6
7
8
9
10
11
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
}),
],
})
export class ConfigurationModule { }
이 파일을 ‘app.module.ts’ 파일에 import 해주면 환경변수를 사용할 준비는 끝난 것이다.
그 외로 DTO를 사용하기위한 APP_PIPE, TypeORM을 사용하기위한 라이브러리들을 import 해주면 된다.
또한 JWT를 사용하기위해 JwtModule, JwtService 를 import 해준다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import { Module, ValidationPipe } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { APP_PIPE } from '@nestjs/core';
import { ConfigurationModule } from './configuration.module';
import { JwtService } from '@nestjs/jwt';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT),
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_NAME,
entities: ['dist/entities/**/*.js'],
synchronize: process.env.DB_SYNCHRONIZE === 'true',
}),
ConfigurationModule,
],
controllers: [AppController],
providers: [
AppService,
JwtService,
{
provide: APP_PIPE,
useClass: ValidationPipe,
},
],
})
export class AppModule { }
위와 같이 설정하면 Jwt를 사용하기위한 Module 세팅은 완료되었다.
이제 로그인을 담당할 module을 세팅해보자.
1
nest g mo auth
위의 명령어를 이용해 ‘auth.module.ts’ 라는 파일을 만든다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { Module } from '@nestjs/common';
import { AuthService } from './auth.service';
import { PassportModule } from '@nestjs/passport';
import { JwtModule } from '@nestjs/jwt';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from 'src/entities/user.entity';
import { UserSecurity } from 'src/entities/user.security.entity';
import { AuthController } from './auth.controller';
import { UserDeleted } from 'src/entities/user.deleted.entity';
import { ConfigurationModule } from 'src/configuration.module';
@Module({
imports: [
PassportModule,
JwtModule.register({
secret: process.env.SECRET_KEY,
signOptions: { expiresIn: '60m' },
}),
TypeOrmModule.forFeature([User, UserSecurity, UserDeleted]),
ConfigurationModule,
],
providers: [AuthService],
controllers: [AuthController],
})
export class AuthModule { }
인증프로세스를 위한 PassportModule과 Jwt 를 사용하기위한 JwtModule를 각각 import 해준다.
그리고 Jwt의 인증토큰을 암호화하기위한 SECRET_KEY를 환경변수로 설정한다.
또한 토큰이 탈취당했을때, 이를 계속 사용할 수 없도록 토큰의 만료시간을 설정한다.
나는 60분으로 설정했다.
TypeORM에서 사용할 Entity들을 설정해주고, 환경변수 사용을위한 ConfigurationModule 또한 import 해준다.
JWT 전략 설정
1
2
3
4
5
//payload.interface.ts
export interface Payload {
email: string;
sub: string;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//jwt.strategy.ts
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { Payload } from './paylode.interface';
import { AuthService } from '../auth.service';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private authService: AuthService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.SECRET_KEY,
});
}
async validate(payload: Payload) {
const user = await this.authService.JwtValidateUser(payload);
if (!user) {
throw new UnauthorizedException();
}
return user;
}
}
위와 같이 payload 즉 인증을 위한 interface를 만든다.
그리고 jwt를 토큰으로 만들고, 클라이언트가 보낸 jwt가 제대로된 토큰인지를 인증하는 메소드를 만든다.
secretOrKey 는 환경변수로 설정해 외부에 유출되지 않도록 한다.
마치며
오늘은 JWT로 로그인 시스템을 만들기위한 Module과 JWT 전략을 설정해보았다.
코드가 길어질 것 같아 몇개의 게시물로 나눠서 작성할 예정이다.