1
- import { Injectable , OnModuleInit } from '@nestjs/common' ;
1
+ import { Inject , Injectable , OnModuleInit } from '@nestjs/common' ;
2
2
import { JwtService } from '@nestjs/jwt' ;
3
3
import * as bcrypt from 'bcrypt' ;
4
+ import Redis from 'ioredis' ;
4
5
import { v4 as uuid4 } from 'uuid' ;
5
6
6
7
import { LoginDto } from './dto/login.dto' ;
@@ -11,48 +12,25 @@ import { UsersRepository } from '@users/users.repository';
11
12
interface RefreshTokenData {
12
13
userId : number ;
13
14
nickname : string ;
14
- expiredAt : Date ;
15
15
}
16
16
17
17
@Injectable ( )
18
- export class AuthService implements OnModuleInit {
19
- private refreshTokens : Record < string , RefreshTokenData > = { } ;
20
- private readonly REFRESH_TOKEN_CONFIG = {
21
- EXPIRE_INTERVAL : 7 * 24 * 60 * 60 * 1000 , // 7일
22
- CLEANUP_INTERVAL : 60 * 60 * 1000 , // 1시간
23
- } as const ;
18
+ export class AuthService {
19
+ private readonly REFRESH_TOKEN_TTL = 7 * 24 * 60 * 60 ;
24
20
25
21
constructor (
26
22
private readonly jwtService : JwtService ,
27
23
private readonly usersRepository : UsersRepository ,
24
+ @Inject ( 'REDIS_REFRESH_TOKEN' ) private readonly refreshTokensRedisClient : Redis ,
28
25
) { }
29
26
30
- getInfo ( refreshToken : string ) {
31
- const user = this . refreshTokens [ refreshToken ] ;
32
- return user ? user . userId : null ;
27
+ async getInfo ( refreshToken : string ) {
28
+ const refreshTokenData : RefreshTokenData = JSON . parse ( await this . refreshTokensRedisClient . get ( refreshToken ) ) ;
29
+ return refreshTokenData ? refreshTokenData . userId : null ;
33
30
}
34
31
35
32
getRefreshTokenExpireTime ( ) {
36
- return this . REFRESH_TOKEN_CONFIG . EXPIRE_INTERVAL ;
37
- }
38
-
39
- onModuleInit ( ) {
40
- this . startPeriodicCleanup ( ) ;
41
- }
42
-
43
- private startPeriodicCleanup ( ) {
44
- setInterval ( ( ) => {
45
- this . cleanupExpiredTokens ( ) ;
46
- } , this . REFRESH_TOKEN_CONFIG . CLEANUP_INTERVAL ) ;
47
- }
48
-
49
- private cleanupExpiredTokens ( ) {
50
- const now = new Date ( ) ;
51
- const expiredTokens = Object . keys ( this . refreshTokens ) . filter ( ( token ) => this . refreshTokens [ token ] . expiredAt < now ) ;
52
-
53
- expiredTokens . forEach ( ( token ) => {
54
- this . removeRefreshToken ( token ) ;
55
- } ) ;
33
+ return this . REFRESH_TOKEN_TTL ;
56
34
}
57
35
58
36
async validateUser ( loginDto : LoginDto ) {
@@ -65,35 +43,32 @@ export class AuthService implements OnModuleInit {
65
43
return { userId : user . userId , nickname : user . nickname } ;
66
44
}
67
45
68
- generateRefreshToken ( userId : number , nickname : string ) {
46
+ async generateRefreshToken ( userId : number , nickname : string ) {
69
47
const token = uuid4 ( ) ;
70
- this . refreshTokens [ token ] = {
48
+ const tokenData : RefreshTokenData = {
71
49
userId,
72
50
nickname,
73
- expiredAt : new Date ( Date . now ( ) + this . REFRESH_TOKEN_CONFIG . EXPIRE_INTERVAL ) ,
74
51
} ;
52
+
53
+ await this . refreshTokensRedisClient . set ( token , JSON . stringify ( tokenData ) , 'EX' , this . REFRESH_TOKEN_TTL ) ;
75
54
return token ;
76
55
}
77
56
78
57
async generateAccessToken ( refreshToken : string ) {
79
- await this . validateRefreshToken ( refreshToken ) ;
80
- return this . jwtService . sign ( this . refreshTokens [ refreshToken ] , {
58
+ const tokenData : RefreshTokenData = await this . validateRefreshToken ( refreshToken ) ;
59
+ return this . jwtService . sign ( tokenData , {
81
60
expiresIn : '2d' ,
82
61
secret : process . env . JWT_ACCESS_SECRET ,
83
62
} ) ;
84
63
}
85
64
86
65
private async validateRefreshToken ( refreshToken : string ) {
87
- const tokenData = this . refreshTokens [ refreshToken ] ;
66
+ const tokenData = await this . refreshTokensRedisClient . get ( refreshToken ) ;
88
67
if ( ! tokenData ) throw RefreshTokenException . invalid ( ) ;
89
-
90
- if ( tokenData . expiredAt < new Date ( ) ) {
91
- this . removeRefreshToken ( refreshToken ) ;
92
- throw RefreshTokenException . expired ( ) ;
93
- }
68
+ return JSON . parse ( tokenData ) ;
94
69
}
95
70
96
- removeRefreshToken ( refreshToken : string ) {
97
- delete this . refreshTokens [ refreshToken ] ;
71
+ async removeRefreshToken ( refreshToken : string ) {
72
+ await this . refreshTokensRedisClient . del ( refreshToken ) ;
98
73
}
99
74
}
0 commit comments