Skip to content

Commit 65d00bc

Browse files
feat: refresh token 인증 과정에서 db 참조하게 구현
1 parent a8f740a commit 65d00bc

File tree

4 files changed

+67
-37
lines changed

4 files changed

+67
-37
lines changed

apps/backend/src/auth/auth.controller.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,11 @@ export class AuthController {
4141
// 네이버 인증 후 사용자 정보 반환
4242
const user = req.user;
4343

44-
// primary Key인 id 포함 payload 생성, access token 만들기
45-
const payload = { sub: user.id };
46-
const accessToken = this.tokenService.generateAccessToken(payload);
44+
// access token 만들기
45+
const accessToken = this.tokenService.generateAccessToken(user.id);
4746

48-
// access token 만들어서 db에도 저장
49-
const refreshToken = this.tokenService.generateRefreshToken();
50-
this.authService.updateRefreshToken(user.id, refreshToken);
47+
// refresh token 만들어서 db에도 저장
48+
const refreshToken = await this.tokenService.generateRefreshToken(user.id);
5149

5250
// 토큰을 쿠키에 담아서 메인 페이지로 리디렉션
5351
this.tokenService.setAccessTokenCookie(res, accessToken);
@@ -69,13 +67,11 @@ export class AuthController {
6967
/// 카카오 인증 후 사용자 정보 반환
7068
const user = req.user;
7169

72-
// primary Key인 id 포함 payload 생성, access token 만들기
73-
const payload = { sub: user.id };
74-
const accessToken = this.tokenService.generateAccessToken(payload);
70+
// access token 만들기
71+
const accessToken = this.tokenService.generateAccessToken(user.id);
7572

76-
// access token 만들어서 db에도 저장
77-
const refreshToken = this.tokenService.generateRefreshToken();
78-
this.authService.updateRefreshToken(user.id, refreshToken);
73+
// refresh token 만들어서 db에도 저장
74+
const refreshToken = await this.tokenService.generateRefreshToken(user.id);
7975

8076
// 토큰을 쿠키에 담아서 메인 페이지로 리디렉션
8177
this.tokenService.setAccessTokenCookie(res, accessToken);

apps/backend/src/auth/auth.service.ts

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,18 +61,4 @@ export class AuthService {
6161
// DB에 있는 값과 일치하는지 비교한다
6262
return user.refreshToken === refreshToken;
6363
}
64-
65-
async updateRefreshToken(id: number, refreshToken: string) {
66-
// 유저를 찾는다.
67-
const user = await this.userRepository.findOneBy({ id });
68-
69-
// 유저가 없으면 오류
70-
if (!user) {
71-
throw new UserNotFoundException();
72-
}
73-
74-
// 유저의 현재 REFRESH TOKEN 갱신
75-
user.refreshToken = refreshToken;
76-
await this.userRepository.save(user);
77-
}
7864
}

apps/backend/src/auth/token/token.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@ import { Module } from '@nestjs/common';
22
import { JwtModule } from '@nestjs/jwt';
33
import { TokenService } from './token.service';
44
import { ConfigModule, ConfigService } from '@nestjs/config';
5+
import { UserModule } from '../../user/user.module';
56

67
@Module({
78
imports: [
9+
UserModule,
810
ConfigModule, // ConfigModule 등록
911
JwtModule.registerAsync({
1012
imports: [ConfigModule], // ConfigModule에서 환경 변수 로드

apps/backend/src/auth/token/token.service.ts

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { Injectable } from '@nestjs/common';
22
import { JwtService } from '@nestjs/jwt';
33
import { Response } from 'express';
44
import { v4 as uuidv4 } from 'uuid';
5+
import { UserRepository } from '../../user/user.repository';
6+
import { UserNotFoundException } from '../../exception/user.exception';
7+
import { InvalidTokenException } from '../../exception/invalid.exception';
58

69
const HOUR = 60 * 60;
710
const DAY = 24 * 60 * 60;
@@ -10,21 +13,27 @@ const MS_HALF_YEAR = 6 * 30 * 24 * 60 * 60 * 1000;
1013

1114
@Injectable()
1215
export class TokenService {
13-
constructor(private readonly jwtService: JwtService) {}
16+
constructor(
17+
private readonly jwtService: JwtService,
18+
private readonly userRepository: UserRepository,
19+
) {}
1420

15-
generateAccessToken(payload: any): string {
21+
generateAccessToken(userId: number): string {
22+
const payload = { sub: userId };
1623
return this.jwtService.sign(payload, {
1724
expiresIn: HOUR,
1825
});
1926
}
2027

21-
generateRefreshToken(): string {
22-
const payload = {
23-
jti: uuidv4(),
24-
};
25-
return this.jwtService.sign(payload, {
28+
async generateRefreshToken(userId: number): Promise<string> {
29+
const payload = { sub: userId, jti: uuidv4() };
30+
const refreshToken = this.jwtService.sign(payload, {
2631
expiresIn: FIVE_MONTHS,
2732
});
33+
34+
await this.updateRefreshToken(userId, refreshToken);
35+
36+
return refreshToken;
2837
}
2938

3039
generateInviteToken(workspaceId: number, role: string): string {
@@ -42,16 +51,23 @@ export class TokenService {
4251
});
4352
}
4453

45-
// 후에 DB 로직 (지금은 refreshToken이 DB로 관리 X)
46-
// 추가될 때를 위해 일단 비동기 선언
4754
async refreshAccessToken(refreshToken: string): Promise<string> {
48-
// refreshToken을 검증한다
55+
// refreshToken 1차 검증한다
4956
const decoded = this.jwtService.verify(refreshToken, {
5057
secret: process.env.JWT_SECRET,
5158
});
5259

60+
// 검증된 토큰에서 사용자 ID 추출
61+
const userId = decoded.sub;
62+
63+
// DB에 저장된 refreshToken과 비교
64+
const isValid = await this.compareStoredRefreshToken(userId, refreshToken);
65+
if (!isValid) {
66+
throw new InvalidTokenException();
67+
}
68+
5369
// 새로운 accessToken을 발급한다
54-
return this.generateAccessToken({ sub: decoded.sub });
70+
return this.generateAccessToken(decoded.sub);
5571
}
5672

5773
setAccessTokenCookie(response: Response, accessToken: string): void {
@@ -86,4 +102,34 @@ export class TokenService {
86102
sameSite: 'strict',
87103
});
88104
}
105+
106+
private async compareStoredRefreshToken(
107+
id: number,
108+
refreshToken: string,
109+
): Promise<boolean> {
110+
// 유저를 찾는다.
111+
const user = await this.userRepository.findOneBy({ id });
112+
113+
// 유저가 없으면 오류
114+
if (!user) {
115+
throw new UserNotFoundException();
116+
}
117+
118+
// DB에 있는 값과 일치하는지 비교한다
119+
return user.refreshToken === refreshToken;
120+
}
121+
122+
private async updateRefreshToken(id: number, refreshToken: string) {
123+
// 유저를 찾는다.
124+
const user = await this.userRepository.findOneBy({ id });
125+
126+
// 유저가 없으면 오류
127+
if (!user) {
128+
throw new UserNotFoundException();
129+
}
130+
131+
// 유저의 현재 REFRESH TOKEN 갱신
132+
user.refreshToken = refreshToken;
133+
await this.userRepository.save(user);
134+
}
89135
}

0 commit comments

Comments
 (0)