diff --git a/server/src/auth/signin/application/signin.service.ts b/server/src/auth/signin/application/signin.service.ts index 741c218..aa149e7 100644 --- a/server/src/auth/signin/application/signin.service.ts +++ b/server/src/auth/signin/application/signin.service.ts @@ -23,14 +23,14 @@ export class SigninService { throw new BadRequestException('패스워드가 일치 하지 않습니다') } - const accessTokenExpireTime = this.jwtProvider.createAccessTokenExpireTime() - const refreshTokenExpireTime = this.jwtProvider.createRefreshTokenExpireTime() + const generateAccessToken = this.jwtProvider.generateAccessToken(member.memberId) + const generateRefreshToken = this.jwtProvider.generateRefreshToken(member.memberId) return { - accessToken: this.jwtProvider.generateAccessToken(member.memberId, accessTokenExpireTime), - refreshToken: this.jwtProvider.generateRefreshToken(member.memberId, refreshTokenExpireTime), - accessTokenExpireTime: accessTokenExpireTime, - refreshTokenExpireTime: refreshTokenExpireTime, + accessToken: generateAccessToken.accessToken, + accessTokenExpireTime: generateAccessToken.accessTokenExpireTime, + refreshToken: generateRefreshToken.refreshToken, + refreshTokenExpireTime: generateRefreshToken.refreshTokenExpireTime, } } } diff --git a/server/src/auth/signup/application/signup.service.ts b/server/src/auth/signup/application/signup.service.ts index 305114d..bdec388 100644 --- a/server/src/auth/signup/application/signup.service.ts +++ b/server/src/auth/signup/application/signup.service.ts @@ -22,14 +22,14 @@ export class SignupService { new Member({ email: email, password: hashedPassword, memberName: memberName }), ) - const accessTokenExpireTime = this.jwtProvider.createAccessTokenExpireTime() - const refreshTokenExpireTime = this.jwtProvider.createRefreshTokenExpireTime() + const generateAccessToken = this.jwtProvider.generateAccessToken(id) + const generateRefreshToken = this.jwtProvider.generateRefreshToken(id) return { - accessToken: this.jwtProvider.generateAccessToken(id, accessTokenExpireTime), - refreshToken: this.jwtProvider.generateRefreshToken(id, refreshTokenExpireTime), - accessTokenExpireTime: accessTokenExpireTime, - refreshTokenExpireTime: refreshTokenExpireTime, + accessToken: generateAccessToken.accessToken, + accessTokenExpireTime: generateAccessToken.accessTokenExpireTime, + refreshToken: generateRefreshToken.refreshToken, + refreshTokenExpireTime: generateRefreshToken.refreshTokenExpireTime, } } } diff --git a/server/src/jwt/jwt.provider.test.ts b/server/src/jwt/jwt.provider.test.ts index ee1f105..76f66a6 100644 --- a/server/src/jwt/jwt.provider.test.ts +++ b/server/src/jwt/jwt.provider.test.ts @@ -1,13 +1,14 @@ import { Test, TestingModule } from '@nestjs/testing' import { JwtProvider } from './jwt.provider' import { BadRequestException, UnauthorizedException } from '@nestjs/common' +import { TokenType } from './token-type.enum' describe('JwtProvider class', () => { let jwtProvider: JwtProvider let INVALID_ACCESS_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjp7Im1lbWJlcklkIjoxLCJlbWFpbCI6ImFiY0BlbWFpbC5jb20iLCJtZW1iZXJOYW1lIjoi7ZmN6ri464-ZIiwibWVtYmVyVHlwZSI6IkdFTkVSQUwiLCJwYXNzd29yZCI6IjEyMzQ1Njc4IiwicmVmcmVzaFRva2VuIjoiZXlKaGJHY2lPaUpJIiwidG9rZW5FeHBpcmF0aW9uVGltZSI6IjIwMjMtMDktMDFUMjM6MTA6MDAuMDA5WiIsInJvbGUiOiJVU0VSIiwiY3JlYXRlVGltZSI6IjIwMjMtMDktMDFUMjM6MTA6MDAuMDA5WiIsInVwZGF0ZVRpbWUiOiIyMDIzLTA5LTAxVDIzOjEwOjAwLjAwOVoiLCJjcmVhdGVCeSI6Iu2Zjeq4uOuPmSIsIm1vZGlmaWVkQnkiOiLquYDssqDsiJgifSwiaWF0IjoxNjk0MzEzOTIyLCJleHAiOjE2OTQ0MDAzMjJ9.F5gN5mkLFk6nET2pJ78_sTdb_YIStT7u8ei7rfK1I123' - const Id = 1 + const ID = 1 const ACCESS_TOKEN_EXPIRE = new Date(Date.now() + 86400000) const REFRESH_TOKEN_EXPIRE = new Date(Date.now() + 1210500000) @@ -22,7 +23,7 @@ describe('JwtProvider class', () => { describe('generateAccessToken method', () => { context('사용자 정보가 주어 질 때', () => { it('accessToken을 리턴 해야 한다', () => { - const accessToken = jwtProvider.generateAccessToken(Id, ACCESS_TOKEN_EXPIRE) + const accessToken = jwtProvider.generateAccessToken(ID) expect(accessToken).not.toEqual( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjp7Im1lbWJlcklkIjoxLCJlbWFpbCI6ImFiY0BlbWFpbC5jb20iLCJtZW1iZXJOYW1lIjoi7ZmN6ri464-ZIiwibWVtYmVyVHlwZSI6IkdFTkVSQUwiLCJwYXNzd29yZCI6IjEyMzQ1Njc4IiwicmVmcmVzaFRva2VuIjoiZXlKaGJHY2lPaUpJIiwidG9rZW5FeHBpcmF0aW9uVGltZSI6IjIwMjMtMDktMDFUMjM6MTA6MDAuMDA5WiIsInJvbGUiOiJVU0VSIiwiY3JlYXRlVGltZSI6IjIwMjMtMDktMDFUMjM6MTA6MDAuMDA5WiIsInVwZGF0ZVRpbWUiOiIyMDIzLTA5LTAxVDIzOjEwOjAwLjAwOVoiLCJjcmVhdGVCeSI6Iu2Zjeq4uOuPmSIsIm1vZGlmaWVkQnkiOiLquYDssqDsiJgifSwiaWF0IjoxNjk0MzEzOTIyLCJleHAiOjE2OTQ0MDAzMjJ9.F5gN5mkLFk6nET2pJ78_sTdb_YIStT7u8ei7rfK1I7c', @@ -32,7 +33,7 @@ describe('JwtProvider class', () => { context('id가 null이 주어지면', () => { it('BadRequestException를 던져야 한다', () => { try { - jwtProvider.generateAccessToken(null, ACCESS_TOKEN_EXPIRE) + jwtProvider.generateAccessToken(null) } catch (e) { expect(e).toBeInstanceOf(BadRequestException) expect(e.message).toEqual('id는 null이 될 수 없습니다') @@ -42,7 +43,7 @@ describe('JwtProvider class', () => { context('id가 undefined이 주어지면', () => { it('BadRequestException를 던져야 한다', () => { try { - jwtProvider.generateAccessToken(undefined, ACCESS_TOKEN_EXPIRE) + jwtProvider.generateAccessToken(undefined) } catch (e) { expect(e).toBeInstanceOf(BadRequestException) expect(e.message).toEqual('id는 undefined이 될 수 없습니다') @@ -54,7 +55,7 @@ describe('JwtProvider class', () => { describe('generateRefreshToken method', () => { context('사용자 정보가 주어 질 때', () => { it('refreshToken을 리턴 해야 한다', () => { - const refreshToken = jwtProvider.generateRefreshToken(Id, REFRESH_TOKEN_EXPIRE) + const refreshToken = jwtProvider.generateRefreshToken(ID) expect(refreshToken).not.toEqual( 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjp7Im1lbWJlcklkIjoxLCJlbWFpbCI6ImFiY0BlbWFpbC5jb20iLCJtZW1iZXJOYW1lIjoi7ZmN6ri464-ZIiwibWVtYmVyVHlwZSI6IkdFTkVSQUwiLCJwYXNzd29yZCI6IjEyMzQ1Njc4IiwicmVmcmVzaFRva2VuIjoiZXlKaGJHY2lPaUpJIiwidG9rZW5FeHBpcmF0aW9uVGltZSI6IjIwMjMtMDktMDFUMjM6MTA6MDAuMDA5WiIsInJvbGUiOiJVU0VSIiwiY3JlYXRlVGltZSI6IjIwMjMtMDktMDFUMjM6MTA6MDAuMDA5WiIsInVwZGF0ZVRpbWUiOiIyMDIzLTA5LTAxVDIzOjEwOjAwLjAwOVoiLCJjcmVhdGVCeSI6Iu2Zjeq4uOuPmSIsIm1vZGlmaWVkQnkiOiLquYDssqDsiJgifSwiaWF0IjoxNjk0MzEzOTIyLCJleHAiOjE2OTQ0MDAzMjJ9.F5gN5mkLFk6nET2pJ78_sTdb_YIStT7u8ei7rfK1I7c', @@ -64,7 +65,7 @@ describe('JwtProvider class', () => { context('id가 null이 주어지면', () => { it('BadRequestException를 던져야 한다', () => { try { - jwtProvider.generateRefreshToken(null, REFRESH_TOKEN_EXPIRE) + jwtProvider.generateRefreshToken(null) } catch (e) { expect(e).toBeInstanceOf(BadRequestException) expect(e.message).toEqual('id는 null이 될 수 없습니다') @@ -74,7 +75,7 @@ describe('JwtProvider class', () => { context('id가 undefined이 주어지면', () => { it('BadRequestException를 던져야 한다', () => { try { - jwtProvider.generateRefreshToken(undefined, REFRESH_TOKEN_EXPIRE) + jwtProvider.generateRefreshToken(undefined) } catch (e) { expect(e).toBeInstanceOf(BadRequestException) expect(e.message).toEqual('id는 undefined이 될 수 없습니다') @@ -86,7 +87,8 @@ describe('JwtProvider class', () => { describe('validateToken method', () => { context('accessToken이 검증을 성공하면', () => { it('id를 리턴 해야 한다.', () => { - const payload = jwtProvider.validateToken(jwtProvider.generateAccessToken(Id, ACCESS_TOKEN_EXPIRE)) + const generateAccessToken = jwtProvider.generateAccessToken(ID) + const payload = jwtProvider.validateToken(generateAccessToken.accessToken) expect(payload).toEqual(1) }) @@ -152,4 +154,25 @@ describe('JwtProvider class', () => { }) }) }) + + describe('generateToken method', () => { + context('id와 accessToken 만료 시간, Access Type이 주어지면', () => { + it('AccessToken을 리턴해야 한다', () => { + const accessToken = jwtProvider.generateToken(ID, ACCESS_TOKEN_EXPIRE, TokenType.ACCESS) + + expect(accessToken).not.toEqual( + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjoxLCJpYXQiOjE2OTQ2NjY2MTksImV4cCI6MTY5NDY2NzI5Mywic3ViIjoiQUNDRVNTIn0.yrr0muDm32ddItUb3HAAR_bDapXp3t-tKFApU2Wowh8', + ) + }) + }) + context('id와 refreshToken 만료 시간, Refresh Type이 주어지면', () => { + it('RefreshToken을 리턴해야 한다', () => { + const refreshToken = jwtProvider.generateToken(ID, REFRESH_TOKEN_EXPIRE, TokenType.REFRESH) + + expect(refreshToken).not.toEqual( + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXlsb2FkIjoxLCJpYXQiOjE2OTQ2NjY2NDUsImV4cCI6MTY5NDY2NzQwNywic3ViIjoiUkVGUkVTSCJ9.twLp5ynQZaiAUF9DHNk9Z2xh-GaDeF5QAxk4JA2qW1I', + ) + }) + }) + }) }) diff --git a/server/src/jwt/jwt.provider.ts b/server/src/jwt/jwt.provider.ts index ee02780..6e47c08 100644 --- a/server/src/jwt/jwt.provider.ts +++ b/server/src/jwt/jwt.provider.ts @@ -1,29 +1,39 @@ import { Injectable, BadRequestException, UnauthorizedException } from '@nestjs/common' import * as jwt from 'jsonwebtoken' import * as dotenv from 'dotenv' +import { TokenType } from './token-type.enum' dotenv.config() @Injectable() export class JwtProvider { - generateAccessToken(id: number, expireTime: Date) { - if (id == undefined || id == null) { - throw new BadRequestException(`id는 ${id}이 될 수 없습니다`) + generateAccessToken(id: number) { + const accessTokenExpireTime = this.createAccessTokenExpireTime() + const accessToken = this.generateToken(id, accessTokenExpireTime, TokenType.ACCESS) + + return { + accessToken: accessToken, + accessTokenExpireTime: accessTokenExpireTime, } + } - return jwt.sign({ payload: id }, process.env.JWT_SECRET, { - subject: 'ACCESS', - expiresIn: expireTime.getMilliseconds(), - }) + generateRefreshToken(id: number) { + const refreshTokenExpireTime = this.createRefreshTokenExpireTime() + const refreshToken = this.generateToken(id, refreshTokenExpireTime, TokenType.REFRESH) + + return { + refreshToken: refreshToken, + refreshTokenExpireTime: refreshTokenExpireTime, + } } - generateRefreshToken(id: number, expireTime: Date) { + generateToken(id: number, expireTime: Date, tokenType: string) { if (id == undefined || id == null) { throw new BadRequestException(`id는 ${id}이 될 수 없습니다`) } return jwt.sign({ payload: id }, process.env.JWT_SECRET, { - subject: 'REFRESH', + subject: tokenType, expiresIn: expireTime.getMilliseconds(), }) } diff --git a/server/src/jwt/token-type.enum.ts b/server/src/jwt/token-type.enum.ts new file mode 100644 index 0000000..461cbd7 --- /dev/null +++ b/server/src/jwt/token-type.enum.ts @@ -0,0 +1,4 @@ +export enum TokenType { + ACCESS = 'ACCESS', + REFRESH = 'REFRESH', +}