๐Ÿ” Spring Security + JWT + Redis ์ธ์ฆ ๊ตฌ์กฐ ์ •๋ฆฌ

๊น€์ •๊ทœยท2025๋…„ 6์›” 19์ผ

โœ… ์ „์ฒด ํ๋ฆ„ ์š”์•ฝ

JWT๋Š” ๋ฌด์ƒํƒœ ์ธ์ฆ ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์—, ํ† ํฐ์„ ํด๋ผ์ด์–ธํŠธ์—๋งŒ ์ €์žฅํ•˜๋ฉด ์„œ๋ฒ„๋Š” ์ƒํƒœ๋ฅผ ๊ธฐ์–ตํ•˜์ง€ ๋ชปํ•จ.
์ด๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด Redis๋ฅผ ์‚ฌ์šฉํ•ด ๋กœ๊ทธ์•„์›ƒ๋œ ํ† ํฐ์ด๋‚˜ ๊ฐ•์ œ๋กœ ๋งŒ๋ฃŒ์‹œํ‚ฌ ํ† ํฐ์„ ๊ด€๋ฆฌํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•จ.


๐Ÿงญ ์ธ์ฆ ํ๋ฆ„ ์ „์ฒด ๊ตฌ์กฐ

1. ๋กœ๊ทธ์ธ ์‹œ

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋กœ๊ทธ์ธ ์š”์ฒญ โ†’ ์„œ๋ฒ„๊ฐ€ JWT ๋ฐœ๊ธ‰ (access + optional refresh)
  • ํ† ํฐ์€ ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅ (์˜ˆ: localStorage, cookie)

2. ์š”์ฒญ ์‹œ

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ Authorization ํ—ค๋”์— ํ† ํฐ ํฌํ•จํ•˜์—ฌ API ํ˜ธ์ถœ
  • ์„œ๋ฒ„์—์„œ๋Š” ํ•„ํ„ฐ์—์„œ JWT๋ฅผ ๋””์ฝ”๋”ฉ โ†’ ์‚ฌ์šฉ์ž ์ •๋ณด ์ถ”์ถœ
  • ์œ ํšจํ•˜๋‹ค๋ฉด SecurityContextHolder์— ์‚ฌ์šฉ์ž ์ •๋ณด ์ €์žฅ โ†’ ์ดํ›„ ์š”์ฒญ์—์„œ ์ธ์ฆ ์ •๋ณด ์‚ฌ์šฉ ๊ฐ€๋Šฅ

3. ๋กœ๊ทธ์•„์›ƒ ์‹œ

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ
  • ์„œ๋ฒ„๋Š” ํ•ด๋‹น JWT๋ฅผ Redis ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ €์žฅ + TTL์€ ํ† ํฐ์˜ ๋‚จ์€ ๋งŒ๋ฃŒ ์‹œ๊ฐ„๋งŒํผ ์„ค์ •
  • ์ดํ›„ ์ด ํ† ํฐ์œผ๋กœ ์š”์ฒญ์ด ์˜ค๋ฉด Redis์—์„œ ์ฐจ๋‹จ๋จ

4. ํ† ํฐ ๊ฒ€์ฆ ์‹œ (ํ•„ํ„ฐ ๋‚ด๋ถ€)

if (isValid(jwt)) {
    if (!redisService.hasKey(jwt)) {
        Authentication auth = getAuthentication(jwt);
        SecurityContextHolder.getContext().setAuthentication(auth);
    } else {
        // ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋ก๋œ ํ† ํฐ โ†’ ์ธ์ฆ ์‹คํŒจ ์ฒ˜๋ฆฌ
    }
}

๐Ÿ“ฆ Redis์˜ ์—ญํ• 

์—ญํ• ์„ค๋ช…
๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ์ €์žฅ์†Œ๋กœ๊ทธ์•„์›ƒ๋œ JWT๋ฅผ Redis์— ์ €์žฅํ•˜์—ฌ ์ธ์ฆ ๊ฑฐ๋ถ€ ์ฒ˜๋ฆฌ
TTL ๊ธฐ๋ฐ˜ ๊ด€๋ฆฌ๋‚จ์€ ํ† ํฐ ๋งŒ๋ฃŒ ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ Redis์— TTL ์„ค์ • โ†’ ์ž๋™ ์‚ญ์ œ
๋น ๋ฅธ ์กฐํšŒRDB๋ณด๋‹ค ๋น ๋ฅธ in-memory ์กฐํšŒ๋กœ ์ธ์ฆ ์„ฑ๋Šฅ ์ตœ์ ํ™”

๐Ÿ” Redis ์—†์ด ๊ตฌํ˜„ํ•˜๋Š” ๋Œ€์•ˆ์€?

๋ฐฉ์‹๋‹จ์ 
RDB์— ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ํ…Œ์ด๋ธ”๋งค ์š”์ฒญ๋งˆ๋‹ค DB IO โ†’ ์„ฑ๋Šฅ ์ €ํ•˜ + TTL ๊ด€๋ฆฌ ๋ณต์žก
ํด๋ผ์ด์–ธํŠธ์—์„œ๋งŒ ํ† ํฐ ์‚ญ์ œ์„œ๋ฒ„๋Š” ์—ฌ์ „ํžˆ ํ† ํฐ์„ ์œ ํšจํ•˜๋‹ค๊ณ  ํŒ๋‹จํ•จ (๋ณด์•ˆ ์ทจ์•ฝ)
accessToken ์งง๊ฒŒ + refreshToken์ผ์ • ์‹œ๊ฐ„ ๋‚ด accessToken์€ ์—ฌ์ „ํžˆ ์œ ํšจ โ†’ ์‹ค์‹œ๊ฐ„ ์ฐจ๋‹จ ๋ถˆ๊ฐ€

โžก๏ธ ๊ฒฐ๋ก : Redis๋Š” ํ† ํฐ ๋ฌดํšจํ™”์™€ ์„ธ์…˜ ์ œ์–ด๋ฅผ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ๋„ ํผํฌ๋จผ์Šค๊นŒ์ง€ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ๋Š” ์ตœ์ ์˜ ์„ ํƒ์ง€


๐Ÿง  ๋ฉด์ ‘์šฉ ์ •๋ฆฌ ๋ฉ˜ํŠธ

โ€œJWT๋Š” ๋ฌด์ƒํƒœ ์ธ์ฆ ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋กœ๊ทธ์•„์›ƒ์ด๋‚˜ ๊ฐ•์ œ ๋งŒ๋ฃŒ๊ฐ€ ์–ด๋ ค์šด ๋‹จ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด Redis์— ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  TTL์„ ์„ค์ •ํ•จ์œผ๋กœ์จ, ์„œ๋ฒ„ ์ธก์—์„œ ํ† ํฐ์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ฌดํšจํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.โ€

profile
๊ธฐํš๊ณผ ์„ค๊ณ„ ๊ทธ๋ฆฌ๊ณ  ๊ตฌํ˜„๊นŒ์ง€ ํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค

0๊ฐœ์˜ ๋Œ“๊ธ€