๐Ÿ’ป PROJECT/[Spring Boot, React] ๋…์„œ ์Šต๊ด€ ๊ด€๋ฆฌ ์„œ๋น„์Šค

[์„ค๊ณ„์˜์‚ฌ๊ฒฐ์ •] JWT + Redis ์ธ์ฆ

devCloud 2026. 5. 13. 20:58
728x90
AUTH

JWT + Redis ์ธ์ฆ ์„ค๊ณ„ - ์„ธ์…˜ ๋Œ€์‹  JWT๋ฅผ ์„ ํƒํ•œ ์ด์œ 

Booktine์€ ๋กœ๊ทธ์ธ ๊ธฐ๋ฐ˜ ๊ธฐ๋Šฅ์ด ๋งŽ์€ ์„œ๋น„์Šค๋‹ค. ๋”ฐ๋ผ์„œ ์ธ์ฆ ๊ตฌ์กฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์„ค๊ณ„ํ• ์ง€๊ฐ€ ์„œ๋น„์Šค ์ „์ฒด ๊ตฌ์กฐ์— ํฐ ์˜ํ–ฅ์„ ์คฌ๋‹ค.

1. ๋ฐฐ๊ฒฝ

Booktine์€ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๋งŒ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ด ๋งŽ๋‹ค. ๋…์„œ ๊ธฐ๋ก ์ž‘์„ฑ, ๋ฉ”๋ชจ, ์ง„ํ–‰๋ฅ  ๊ด€๋ฆฌ ๋“ฑ ๋Œ€๋ถ€๋ถ„์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์ด ์ธ์ฆ์„ ์ „์ œ๋กœ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ• ์ง€๊ฐ€ ์ค‘์š”ํ•œ ์„ค๊ณ„ ๊ฒฐ์ • ์ค‘ ํ•˜๋‚˜์˜€๋‹ค.

 

ํ•ต์‹ฌ ๊ธฐ์ค€์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•˜๋‹ค.

  • ์„œ๋ฒ„ ํ™•์žฅ์„ฑ
  • ํ”„๋ก ํŠธ์—”๋“œ(React)์™€์˜ ์—ฐ๋™ ํŽธ์˜์„ฑ
  • ๊ตฌํ˜„ ๋ณต์žก๋„

2. ์ธ์ฆ ๋ฐฉ์‹ ๋น„๊ต

๋ฐฉ์‹ ์„ค๋ช… ํ™•์žฅ์„ฑ ๊ตฌํ˜„ ๋‚œ์ด๋„
์„ธ์…˜ ์„œ๋ฒ„ ๋ฉ”๋ชจ๋ฆฌ์— ์ธ์ฆ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ณ , ํด๋ผ์ด์–ธํŠธ๋Š” ์„ธ์…˜ ID๋งŒ ๊ฐ–๋Š”๋‹ค. ๋‚ฎ์Œ (์„œ๋ฒ„ ์ƒํƒœ ์œ ์ง€ ํ•„์š”) ๋‚ฎ์Œ
JWT ์ธ์ฆ ์ •๋ณด๋ฅผ ํ† ํฐ์— ๋‹ด์•„ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ง์ ‘ ๋ณด๊ด€ํ•œ๋‹ค. ๋†’์Œ (Stateless) ์ค‘๊ฐ„
์„ธ์…˜์€ ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๊ณ , JWT๋Š” Stateless ๊ตฌ์กฐ๋ผ๋Š” ์ฐจ์ด๊ฐ€ ๊ฐ€์žฅ ํ•ต์‹ฌ์ด์—ˆ๋‹ค.

3. ์„ธ์…˜์„ ์„ ํƒํ•˜์ง€ ์•Š์€ ์ด์œ 

์„ธ์…˜์€ ๊ตฌํ˜„์ด ๋‹จ์ˆœํ•˜๊ณ  Spring Security์™€์˜ ๊ธฐ๋ณธ ์—ฐ๋™์ด ์ž˜ ๋˜์–ด ์žˆ๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๊ตฌ์กฐ๋ฅผ ๊ณ ๋ คํ–ˆ์„ ๋•Œ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋‹ค.

  • ์„œ๋ฒ„ ๋ฉ”๋ชจ๋ฆฌ์— ์„ธ์…˜ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋ฒ„ ์žฌ์‹œ์ž‘ ์‹œ ๋กœ๊ทธ์ธ ์ƒํƒœ๊ฐ€ ์ดˆ๊ธฐํ™”๋œ๋‹ค.
  • ์„œ๋ฒ„๋ฅผ ์ˆ˜ํ‰ ํ™•์žฅํ•  ๊ฒฝ์šฐ ์„ธ์…˜ ๋™๊ธฐํ™” ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • React ๊ธฐ๋ฐ˜ SPA์™€์˜ ์—ฐ๋™์—์„œ CORS ์„ค์ •์ด ๋ณต์žกํ•ด์งˆ ์ˆ˜ ์žˆ๋‹ค.
  • REST API ๊ตฌ์กฐ์—์„œ๋Š” Stateless ๋ฐฉ์‹์ด ๋” ์ž์—ฐ์Šค๋Ÿฝ๋‹ค.

๋ฌด์—‡๋ณด๋‹ค ํ”„๋ก ํŠธ์—”๋“œ๊ฐ€ React๋กœ ๋ถ„๋ฆฌ๋œ ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์—, ์ฟ ํ‚ค ๊ธฐ๋ฐ˜ ์„ธ์…˜๋ณด๋‹ค ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธ์ฆ์ด ์—ฐ๋™ํ•˜๊ธฐ ๋” ํŽธ๋ฆฌํ•˜๋‹ค๊ณ  ํŒ๋‹จํ–ˆ๋‹ค.


4. ๊ฒฐ์ • - JWT + Redis

Access Token / Refresh Token ๋ฐœ๊ธ‰

JWT๋Š” Access Token๊ณผ Refresh Token ๋‘ ๊ฐ€์ง€๋ฅผ ๋ฐœ๊ธ‰ํ•˜๋Š” ๊ตฌ์กฐ๋กœ ์„ค๊ณ„ํ–ˆ๋‹ค. Access Token์€ ๋งŒ๋ฃŒ ์‹œ๊ฐ„์„ ์งง๊ฒŒ ์„ค์ •ํ•ด ํƒˆ์ทจ ์œ„ํ—˜์„ ์ค„์ด๊ณ , ๋งŒ๋ฃŒ ์‹œ Refresh Token์œผ๋กœ ์žฌ๋ฐœ๊ธ‰๋ฐ›๋„๋ก ํ–ˆ๋‹ค.

JwtProvider์—์„œ๋Š” Access Token๊ณผ Refresh Token ์ƒ์„ฑ, Claim ํŒŒ์‹ฑ, ๋งŒ๋ฃŒ ๊ฒ€์ฆ ๋“ฑ์˜ ํ•ต์‹ฌ JWT ๋กœ์ง์„ ๋‹ด๋‹นํ•œ๋‹ค.
JWT ๋‚ด๋ถ€ Claim ์ •๋ณด๋ฅผ ์ถ”์ถœํ•˜๊ณ , ํ† ํฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋กœ์ง์ด๋‹ค.

 

Refresh Token์„ Redis์— ์ €์žฅํ•œ ์ด์œ 

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

  • ๋กœ๊ทธ์•„์›ƒ ์‹œ Redis์—์„œ Refresh Token์„ ์‚ญ์ œํ•˜๋ฉด ์žฌ๋ฐœ๊ธ‰์ด ๋ถˆ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.
  • Redis TTL ๊ธฐ๋Šฅ์œผ๋กœ ๋งŒ๋ฃŒ ์ฒ˜๋ฆฌ๋ฅผ ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜ ์ €์žฅ์†Œ๋ผ ์กฐํšŒ ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค.
  • RDB์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹๋ณด๋‹ค DB ๋ถ€๋‹ด์ด ์ ๋‹ค.

๋ณ„๋„ Repository ํด๋ž˜์Šค ์—†์ด StringRedisTemplate์„ AuthService์—์„œ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค.

Refresh Token์€ Redis์— TTL๊ณผ ํ•จ๊ป˜ ์ €์žฅ๋œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋งŒ๋ฃŒ ์‹œ๊ฐ„์„ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

๋กœ๊ทธ์ธ ์œ ์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ผ Refresh Token์˜ TTL๋„ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ–ˆ๋‹ค. ๋กœ๊ทธ์ธ ์œ ์ง€๋ฅผ ์„ ํƒํ•˜์ง€ ์•Š์œผ๋ฉด ์ตœ๋Œ€ 12์‹œ๊ฐ„์œผ๋กœ ์ œํ•œํ•œ๋‹ค.

๋กœ๊ทธ์ธ ์œ ์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ผ Refresh Token์˜ TTL์„ ๋‹ค๋ฅด๊ฒŒ ์„ค์ •ํ•ด ๋ณด์•ˆ์„ฑ๊ณผ ์‚ฌ์šฉ์ž ํŽธ์˜์„ฑ ์‚ฌ์ด์˜ ๊ท ํ˜•์„ ๋งž์ท„๋‹ค.
๋กœ๊ทธ์ธ ๋ฐ ํ† ํฐ ๋ฐœ๊ธ‰ ํ๋ฆ„
์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•˜๋ฉด ์„œ๋ฒ„๋Š” Access Token๊ณผ Refresh Token์„ ์ƒ์„ฑํ•œ๋‹ค. Refresh Token์€ Redis์— TTL๊ณผ ํ•จ๊ป˜ ์ €์žฅ๋˜๊ณ , Access Token์€ ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌ๋œ๋‹ค.

 

๋กœ๊ทธ์•„์›ƒ ๋ฐ Access Token ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ

๋กœ๊ทธ์•„์›ƒ ์‹œ์—๋Š” Redis์—์„œ Refresh Token์„ ์‚ญ์ œํ•˜๊ณ , ํ˜„์žฌ Access Token์„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋กํ•œ๋‹ค.

Access Token์€ ๋งŒ๋ฃŒ ์ „๊นŒ์ง€ ์œ ํšจํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋กํ•ด ์žฌ์‚ฌ์šฉ์„ ๋ง‰๋Š”๋‹ค.

๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์˜ TTL์€ Access Token์˜ ๋‚จ์€ ๋งŒ๋ฃŒ ์‹œ๊ฐ„์œผ๋กœ ์„ค์ •ํ–ˆ๋‹ค.

๋กœ๊ทธ์•„์›ƒ ์‹œ Refresh Token์„ Redis์—์„œ ์ œ๊ฑฐํ•˜๊ณ , ํ˜„์žฌ Access Token์„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋กํ•œ๋‹ค.
๋กœ๊ทธ์•„์›ƒ ๋ฐ ํ† ํฐ ๋ฌดํšจํ™” ํ๋ฆ„
๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด Refresh Token์€ Redis์—์„œ ์‚ญ์ œ๋œ๋‹ค. ๋™์‹œ์— ํ˜„์žฌ Access Token์€ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋ก๋˜์–ด ๋งŒ๋ฃŒ ์ „๊นŒ์ง€ ์žฌ์‚ฌ์šฉ๋˜์ง€ ๋ชปํ•˜๋„๋ก ์ฐจ๋‹จ๋œ๋‹ค.

JwtFilter์—์„œ๋Š” ๋งค ์š”์ฒญ๋งˆ๋‹ค ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ๋“ฑ๋ก ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•œ๋‹ค.

JwtFilter๋Š” ์š”์ฒญ๋งˆ๋‹ค Access Token์ด ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋ก๋๋Š”์ง€ ํ™•์ธํ•ด ๋ฌดํšจํ™”๋œ ํ† ํฐ์˜ ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•œ๋‹ค.

 

Access Token ์žฌ๋ฐœ๊ธ‰

Refresh Token ๊ฒ€์ฆ ํ›„ Redis์— ์ €์žฅ๋œ ๊ฐ’๊ณผ ์ผ์น˜ํ•˜๋Š” ๊ฒฝ์šฐ์—๋งŒ ์ƒˆ Access Token์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค.

Refresh Token ๊ฒ€์ฆ ํ›„ Redis ์ €์žฅ๊ฐ’๊ณผ ๋น„๊ตํ•ด ์œ ํšจํ•œ ๊ฒฝ์šฐ์—๋งŒ Access Token์„ ์žฌ๋ฐœ๊ธ‰ํ•œ๋‹ค.
Access Token ์žฌ๋ฐœ๊ธ‰ ํ๋ฆ„
ํด๋ผ์ด์–ธํŠธ๋Š” ๋งŒ๋ฃŒ๋œ Access Token ๋Œ€์‹  Refresh Token์œผ๋กœ ์žฌ๋ฐœ๊ธ‰ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค. ์„œ๋ฒ„๋Š” Redis์— ์ €์žฅ๋œ Refresh Token๊ณผ ๋น„๊ต ๊ฒ€์ฆ ํ›„ ์ƒˆ๋กœ์šด Access Token์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค.

์„ ํƒ ์ด์œ 

  • React ๊ธฐ๋ฐ˜ SPA์™€ ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธ์ฆ ์—ฐ๋™์ด ์ž์—ฐ์Šค๋Ÿฝ๋‹ค.
  • Stateless ๊ตฌ์กฐ๋กœ ์„œ๋ฒ„ ํ™•์žฅ์— ์œ ๋ฆฌํ•˜๋‹ค.
  • Redis TTL๋กœ Refresh Token ๋งŒ๋ฃŒ๋ฅผ ์ž๋™ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋กœ๊ทธ์•„์›ƒ ์‹œ Refresh Token ์‚ญ์ œ + Access Token ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ ๋“ฑ๋ก์œผ๋กœ ๊ฐ•์ œ ๋ฌดํšจํ™”๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

5. JWT์˜ ํ•œ๊ณ„

Access Token์€ ๋งŒ๋ฃŒ ์ „๊นŒ์ง€ ์„œ๋ฒ„์—์„œ ๊ฐ•์ œ๋กœ ๋ฌดํšจํ™”ํ•  ์ˆ˜ ์—†๋‹ค. ๋”ฐ๋ผ์„œ ํƒˆ์ทจ๋œ ๊ฒฝ์šฐ์—๋„ ๋งŒ๋ฃŒ ์‹œ๊ฐ„๊นŒ์ง€๋Š” ์œ ํšจํ•˜๊ฒŒ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.

 

๋‹ค๋งŒ Access Token์˜ ๋งŒ๋ฃŒ ์‹œ๊ฐ„์„ ์งง๊ฒŒ ์„ค์ •ํ•˜๊ณ , ๋กœ๊ทธ์•„์›ƒ ์‹œ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ์ตœ์†Œํ™”ํ–ˆ๋‹ค.

ํ˜„์žฌ Booktine ์„œ๋น„์Šค ๊ทœ๋ชจ์—์„œ๋Š” JWT + Redis ๋ฐฉ์‹์ด ํ™•์žฅ์„ฑ๊ณผ ๊ตฌํ˜„ ๋ณต์žก๋„ ์‚ฌ์ด์—์„œ ๊ฐ€์žฅ ์ ์ ˆํ•œ ๊ท ํ˜•์ด๋ผ๊ณ  ํŒ๋‹จํ–ˆ๋‹ค.
728x90