Hello Kitty Eyes Shut
๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ’ป๊ณต๋ถ€ ๊ธฐ๋ก/๐Ÿ“Œ Backend

[Backend] Redis TTL + JWT

๋ฐ˜์‘ํ˜•

 

 

 

๐Ÿง  Redis TTL

์˜ค๋Š˜์€ JWT + Redis ์ธ์ฆ ์‹œ์Šคํ…œ์—์„œ TTL (Time To Live)์„ ๊ผญ ์„ค์ •ํ•ด์•ผ ํ•˜๋Š” ์ด์œ ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ณ ์ž ํ•œ๋‹ค. ๐Ÿง

 

 


๐Ÿ“š TTL (Time To Live)์ด๋ž€?

TTL์€ Redis์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž๋™์œผ๋กœ ์‚ญ์ œ๋˜๋Š” ์‹œ๊ฐ„์„ ๋งํ•œ๋‹ค.

์ฆ‰, Redis์— ๊ฐ’์„ ์ €์žฅํ•  ๋•Œ ์œ ํšจ ๊ธฐ๊ฐ„์„ ํ•จ๊ป˜ ์„ค์ •ํ•˜๋ฉด, ๊ทธ ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ์ž๋™์œผ๋กœ ์‚ญ์ œ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

redisTemplate.opsForValue().set("RT:userId", refreshToken, Duration.ofMillis(expirationMillis));

 

์œ„์˜ ์ฝ”๋“œ์—์„œ Duration.ofMillis(expirationMillis) ๋ถ€๋ถ„์ด TTL์„ ์„ค์ •ํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

 


๐Ÿง ์™œ TTL์„ ์„ค์ •ํ•ด์•ผ ํ• ๊นŒ?

1๏ธโƒฃ ๋ณด์•ˆ ๐Ÿ”’

๋งŒ์•ฝ ์‚ฌ์šฉ์ž์˜ ํ† ํฐ์ด Redis์— ๋ฌด๊ธฐํ•œ ์ €์žฅ๋œ๋‹ค๋ฉด,

๋กœ๊ทธ์•„์›ƒ ํ›„์—๋„ ํ† ํฐ์ด ๋‚จ์•„ ์žˆ์–ด์„œ ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•  ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ

์•…์˜์ ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ํƒˆ์ทจํ•œ ํ† ํฐ์„ ์˜ค๋žซ๋™์•ˆ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

๐Ÿ‘‰๐Ÿป ์ด๋Ÿด ๋•Œ TTL์„ ์„ค์ •ํ•˜๋ฉด, ํ•ด๋‹น ์‹œ๊ฐ„ ์ดํ›„์—” Redis์—์„œ ์ž๋™ ์‚ญ์ œ๋˜๋ฏ€๋กœ ๋ณด์•ˆ ์‚ฌ๊ณ ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

 

2๏ธโƒฃ ์‹œ์Šคํ…œ ์„ฑ๋Šฅ ๐Ÿƒ‍โ™€๏ธ๐Ÿ’จ

Redis๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜ ์ €์žฅ์†Œ์ด๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋žซ๋™์•ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๊ณ„์† ์Œ“์•„๋‘๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•œ๋‹ค.

๐Ÿ‘‰๐Ÿป ๋”ฐ๋ผ์„œ TTL ์„ค์ •์„ ํ†ตํ•ด ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๋Š” ์ž๋™์œผ๋กœ ์‚ญ์ œ๋˜์–ด Redis๊ฐ€ ๊ฐ€๋ณ๊ฒŒ ์œ ์ง€๋˜๋„๋ก ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

 

3๏ธโƒฃ ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด์„ฑ ๐Ÿ› ๏ธ

TTL์„ ์„ค์ •ํ•ด๋‘๋ฉด, ๋ณ„๋„๋กœ ์‚ญ์ œ ๋กœ์ง์„ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

๐Ÿ‘‰๐Ÿป ๋”ฐ๋ผ์„œ ์ฝ”๋“œ๊ฐ€ ํ›จ์”ฌ ๊ฐ„๊ฒฐํ•ด์ง€๊ณ , ์‹ค์ˆ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

 


๐Ÿ”ฅ JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ ์‹œ์Šคํ…œ์—์„œ์˜ TTL ์„ค์ • ์ „๋žต

JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ ์‹œ์Šคํ…œ์—์„œ๋Š” ์ฃผ๋กœ ์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ํ† ํฐ์„ ์‚ฌ์šฉํ•œ๋‹ค.

ํ† ํฐ ์ข…๋ฅ˜ ์—ญํ•  TTL ๊ถŒ์žฅ๊ฐ’ Redis ์ €์žฅ ํ•„์š”์„ฑ
๐Ÿ”‘ Access Token ์‚ฌ์šฉ์ž ์ธ์ฆ / ์ธ๊ฐ€ ์ˆ˜ํ–‰ โณ 15~30๋ถ„ ๋ณดํ†ต ์ €์žฅํ•˜์ง€ ์•Š์Œ
๐Ÿ”„ Refresh Token AccessToken ์žฌ๋ฐœ๊ธ‰์šฉ โณ 7~14์ผ Redis์— ์ €์žฅ + TTL ์„ค์ •

 


๐Ÿ’ก ์™œ AccessToken์€ Redis์— ์ €์žฅํ•˜์ง€ ์•Š์„๊นŒ?

1๏ธโƒฃ JWT์˜ ๋ณธ์งˆ์€ Stateless ๊ตฌ์กฐ

JWT๋Š” ํ† ํฐ ์ž์ฒด์— ๋ชจ๋“  ์ธ์ฆ ์ •๋ณด (userId, ๊ถŒํ•œ, ๋งŒ๋ฃŒ ์‹œ๊ฐ„ ๋“ฑ)์„ ๋‹ด๊ณ  ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ์„œ๋ฒ„๋Š” JWT๋ฅผ ๋ฐ›์„ ๋•Œ, ์„œ๋ฒ„์˜ ์„ธ์…˜์ด๋‚˜ DB๋ฅผ ์กฐํšŒํ•˜์ง€ ์•Š์•„๋„ ์ด ํ† ํฐ์ด ์œ ํšจํ•œ์ง€ ์ž์ฒด ๊ฒ€์ฆ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰, ์„œ๋ฒ„๋Š” ๊ธฐ์–ต์„ ํ•˜์ง€ ์•Š์•„๋„ ํ† ํฐ๋งŒ ๋ณด๊ณ  ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ Redis์— ๋”ฐ๋กœ ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

 

2๏ธโƒฃ AccessToken์€ ์ˆ˜๋ช…์ด ์งง์Œ

๋ณดํ†ต AccessToken์€ ์ˆ˜๋ช…์„ ์งง๊ฒŒ ์„ค์ •ํ•ด์„œ, ํƒˆ์ทจ๋˜๋”๋ผ๋„ ํ”ผํ•ด๊ฐ€ ์ œํ•œ์ ์ด๊ฒŒ ์„ค๊ณ„๋œ๋‹ค.

๋”ฐ๋ผ์„œ TTL์ด ์งง๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ž˜ ๋ณด๊ด€ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ ๊ตณ์ด ์ €์žฅํ•˜์ง€ ์•Š๊ณ , ์„œ๋ฒ„ ์ž์› ๋‚ญ๋น„๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์ด๋‹ค.

 


โ— AccessToken์„ Redis์— ์ €์žฅํ•˜๋Š” ๊ฒฝ์šฐ

๋ฐ”๋กœ ์œ„์—์„œ AccessToken์€ Redis์— ์ €์žฅํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๊ณ  ํ–ˆ์ง€๋งŒ,, ๐Ÿ˜…

AccessToken์„ Redis์— ์ €์žฅํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋„ ์กด์žฌํ•œ๋‹ค.

 

๋ฐ”๋กœ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผํ•˜๋Š” ๊ฒฝ์šฐ์ด๋‹ค.

 

์œ„์˜ ๋‚ด์šฉ์„ ์ฝ์œผ๋ฉด์„œ,

๐Ÿ’ฌ "JWT๋Š” Stateless๋ผ์„œ ๋กœ๊ทธ์•„์›ƒ ์ฒ˜๋ฆฌ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ๋“ค์—ˆ๋Š”๋ฐ์š”?"

๋ผ๋Š” ์˜๋ฌธ์ ์„ ํ’ˆ์œผ๋ฉฐ AccessToken์ด ํ•„์š”ํ•œ ๊ฒƒ์ด ์•„๋‹Œ๊ฐ€ ์ƒ๊ฐํ•˜์‹  ๋ถ„๋“ค์ด ์žˆ์„ ๊ฒƒ์ด๋‹ค.

 

์ด๊ฑฐ์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•˜์ž๋ฉด,

์›์น™์ ์œผ๋กœ๋Š” AccessToken์ด ๋งŒ๋ฃŒ๋˜๊ธฐ ์ „๊นŒ์ง€๋Š” ํ† ํฐ์ด ์œ ํšจํ•˜๊ธฐ ๋•Œ๋ฌธ์—

๋กœ๊ทธ์•„์›ƒ์„ ํ•ด๋„ ํ† ํฐ์„ ๊ฐ€์ง„ ์‚ฌ๋žŒ์€ ๊ณ„์† ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋œ๋‹ค. ๐Ÿšจ

 

๊ทธ๋ž˜์„œ ํ•„์š”ํ•œ ๊ฒƒ์ด ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์ด๋‹ค.

 

๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค๋Š” ๊ฒƒ์€

1๏ธโƒฃ ๋กœ๊ทธ์•„์›ƒ ์‹œ ํ•ด๋‹น AccessToken์„ Redis์— ์ €์žฅํ•ด๋‘๊ณ 

2๏ธโƒฃ TTL์€ AccessToken์˜ ๋‚จ์€ ๋งŒ๋ฃŒ ์‹œ๊ฐ„๊ณผ ๋™์ผํ•˜๊ฒŒ ์„ค์ •ํ•จ์œผ๋กœ์จ

3๏ธโƒฃ ์ดํ›„ ์š”์ฒญ์ด ๋“ค์–ด์™”์„ ๋•Œ ์ด ํ† ํฐ์ด ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์„œ ๊ฑฐ์ ˆํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๋กœ๊ทธ์•„์›ƒ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด๋‘˜ ์ˆ˜ ์žˆ๋‹ค.

public void blacklistAccessToken(String accessToken, long expirationMillis){
    String tokenHash = DigestUtils.md5DigestAsHex(accessToken.getBytes());
    redisTemplate.opsForValue().set("BL:" + tokenHash, "blacklisted", Duration.ofMillis(expirationMillis));
}

 

๋ฐ˜์‘ํ˜•