JWT #1

Dearยท2025๋…„ 7์›” 31์ผ

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
64/74

๐Ÿ’™ JWT

JSON Web Token
์‚ฌ์šฉ์ž ์ธ์ฆ(Authentication)๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ(Authorization)์— ์‚ฌ์šฉํ•˜๋Š” ํ† ํฐ ๊ธฐ๋ฐ˜ ์ธ์ฆ ๋ฐฉ์‹

์‚ฌ์šฉ์ž์˜ ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋‹ด์•„ ์„œ๋ฒ„ - ํด๋ผ์ด์–ธํŠธ ๊ฐ„์— ์ „๋‹ฌํ•˜๋Š” ์„œ๋ช…๋œ ํ† ํฐ์ด๋‹ค.

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

๐Ÿ’™ ๊ตฌ์„ฑ

์„ธ ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ์„ฑ๋œ ๋ฌด์ž์—ด
xxxxx.yyyyy.zzzzz

๋ถ€๋ถ„๋‚ด์šฉ์„ค๋ช…
Headerํ† ํฐ ํƒ€์ž…๊ณผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ˆ: { "alg": "HS256", "typ": "JWT" }
Payload์‚ฌ์šฉ์ž ์ •๋ณด (Claims)์˜ˆ: userId, role, exp(๋งŒ๋ฃŒ์‹œ๊ฐ„)
Signature์œ„์กฐ ๋ฐฉ์ง€์šฉ ์„œ๋ช…๋น„๋ฐ€ ํ‚ค๋กœ ์„œ๋ช…ํ•˜์—ฌ ์œ„๋ณ€์กฐ ๋ฐฉ์ง€

์‹ค์ œ JWT ๊ตฌ์กฐ ์˜ˆ์‹œ

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiAidXNlcjEiLCAicm9sZSI6ICJVU0VSIiwgImV4cCI6IDE3NTQwMDAwMDB9. XqVfNNjOt-y0IxqFe9fJexBJKrLdKK7-_a9UOi27_xg

  • ์•ž : Header (alg, typ)
  • ์ค‘๊ฐ„ : Payload
  • ๋’ค : Signature (์œ„์กฐ ๋ฐฉ์ง€์šฉ)

๐Ÿ’™ Payload

{
  "sub": "user1",
  "role": "USER",
  "exp": 1754000000
}
ํ‚ค์˜๋ฏธ์˜ˆ์‹œ ๊ฐ’์„ค๋ช…
subSubject (์ฃผ์ฒด)"user1"๋ณดํ†ต ์‚ฌ์šฉ์ž ์‹๋ณ„์ž (์˜ˆ: user ID, ์ด๋ฉ”์ผ ๋“ฑ)
role์‚ฌ์šฉ์ž ๊ถŒํ•œ"USER"์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ (์˜ˆ: ADMIN, USER ๋“ฑ)
expExpiration (๋งŒ๋ฃŒ ์‹œ๊ฐ„)1754000000ํ† ํฐ ๋งŒ๋ฃŒ ์‹œ๊ฐ„ (Unix timestamp)

์‹ค์ œ JWT ์•ˆ์˜ payload

JWT๋Š” base64๋กœ ์ธ์ฝ”๋”ฉ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ์œ„์˜ json์€
eyJzdWIiOiAidXNlcjEiLCAicm9sZSI6ICJVU0VSIiwgImV4cCI6IDE3NTQwMDAwMDB9
๋กœ ๋ณ€ํ˜•๋˜์–ด JWT ์ค‘๊ฐ„ ๋ถ€๋ถ„์œผ๋กœ ๋“ค์–ด๊ฐ„๋‹ค.

๐Ÿ’™ ํ๋ฆ„ (๋กœ๊ทธ์ธ ๊ธฐ๋ฐ˜ ์ธ์ฆ)

1. ์‚ฌ์šฉ์ž ๋กœ๊ทธ์ธ ์„ฑ๊ณต

  • ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋‹ด์€ JWT๋ฅผ ๋ฐœ๊ธ‰
  • ํด๋ผ์ด์–ธํŠธ(๋ธŒ๋ผ์šฐ์ €/์›น)๋Š” ์ด ํ† ํฐ์„ ์ €์žฅ (ex. localStorage, ์ฟ ํ‚ค)

2. ์ดํ›„ ์š”์ฒญ๋งˆ๋‹ค

  • ํด๋ผ์ด์–ธํŠธ๊ฐ€ Authorization: Bearer <JWT> ํ—ค๋”์— ํ† ํฐ์„ ๋‹ด์•„ ์ „์†ก
  • ์„œ๋ฒ„๋Š” ์ด ํ† ํฐ์„ ๊ฒ€์ฆํ•˜์—ฌ ์‚ฌ์šฉ์ž ์ธ์ฆ ์ฒ˜๋ฆฌ

3. ์„œ๋ฒ„๋Š” ์„ธ์…˜์„ ์ €์žฅํ•˜์ง€ ์•Š์Œ

  • JWT ์ž์ฒด์— ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ ์žˆ๋‹ค (stateless)

stateless(๋ฌด์ƒํƒœ) : ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ์˜ ์ด์ „ ์š”์ฒญ ์ƒํƒœ๋ฅผ ๊ธฐ์–ตํ•˜์ง€ ์•Š๋Š” ๊ตฌ์กฐ
stateful(์ƒํƒœ ์œ ์ง€ ๋ฐฉ์‹) : ์„œ๋ฒ„๊ฐ€ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•ด ๋†“๊ณ  ์ƒํƒœ๋ฅผ ๊ธฐ์–ตํ•˜๋Š” ๊ตฌ์กฐ

๐Ÿ’™ ์‚ฌ์šฉ ์‹œ์ 

์ƒํ™ฉJWT ์ ํ•ฉ ์—ฌ๋ถ€
๋ชจ๋ฐ”์ผ ์•ฑ, SPA(React/Vue) ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ์ ํ•ฉ
์„œ๋ฒ„ ๊ฐ„ ํ†ต์‹  ์ธ์ฆ์ ํ•ฉ
๋ณด์•ˆ์ด ๋ฏผ๊ฐํ•˜๊ณ  ๋กœ๊ทธ์•„์›ƒ์ด ์ž์ฃผ ํ•„์š”ํ•œ ์›น์‚ฌ์ดํŠธโš ๏ธ ์„ธ์…˜ ๋ฐฉ์‹์ด ๋‚˜์„ ์ˆ˜ ์žˆ์Œ
POST /login
โ†’ ์‘๋‹ต: JWT ๋ฐœ๊ธ‰

GET /myPage
Authorization: Bearer eyJhbGciOi...

โ†’ ์„œ๋ฒ„๋Š” ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๊ณ  ๋กœ๊ทธ์ธ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด ์‚ฌ์šฉ

๐Ÿ’™ OncePerRequestFilter

Spring Framework์—์„œ ์ œ๊ณตํ•˜๋Š” ์„œ๋ธ”๋ฆฟ ํ•„ํ„ฐ(Filter) ์˜ ์ถ”์ƒ ํด๋ž˜์Šค

javax.servlet.Filter ๋Š” ํ•œ ์š”์ฒญ์—์„œ ์—ฌ๋Ÿฌ ๋ฒˆ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋Š” ์œ„ํ—˜์ด ์žˆ๋‹ค.(์˜ˆ:ํฌ์›Œ๋”ฉ)
OncePerRequestFilter๋Š” ํ•œ ์š”์ฒญ์— ๋”ฑ ํ•œ ๋ฒˆ๋งŒ doFilterInternal() ๋ฉ”์†Œ๋“œ๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅํ•œ๋‹ค.

์ฆ‰, ์ค‘๋ณต ์‹คํ–‰์„ ๋ฐฉ์ง€ํ•˜๋ฉด์„œ ํ•„ํ„ฐ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ฃผ๋Š” ํด๋ž˜์Šค

์‚ฌ์šฉ์œ„์น˜

๋ณดํ†ต Spring Security์—์„œ ์ธ์ฆ/์ธ๊ฐ€ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ JWT ํ•„ํ„ฐ, ๋กœ๊น… ํ•„ํ„ฐ ๋“ฑ์— ์‚ฌ์šฉํ•œ๋‹ค.

ํ๋ฆ„๋„

[์š”์ฒญ] โ†’ [OncePerRequestFilter ๊ตฌํ˜„์ฒด (์˜ˆ: JwtFilter)] โ†’ [๋‹ค์Œ ํ•„ํ„ฐ or ์ปจํŠธ๋กค๋Ÿฌ]

๐Ÿ’™ FilterChain

์ž๋ฐ” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ•„ํ„ฐ๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” ๊ฐ์ฒด์ด๋‹ค.

๋ณดํ†ต doFilter() ๋ฉ”์†Œ๋“œ ์•ˆ์—์„œ ๋‹ค์Œ ํ•„ํ„ฐ ๋˜๋Š” ์„œ๋ธ”๋ฆฟ์œผ๋กœ ์š”์ฒญ์„ ๋„˜๊ธธ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. (์˜ˆ: Spring Security, Logging Filter, JWT Filter ๋“ฑ)

์˜ˆ์‹œ ์ƒํ™ฉ

  • ์ธ์ฆ ํ•„ํ„ฐ : JWT๊ฐ€ ์œ ํšจํ•œ์ง€ ๊ฒ€์‚ฌ ํ›„ chain.doFilter() ํ˜ธ์ถœ
  • ๋กœ๊น… ํ•„ํ„ฐ : ์š”์ฒญ ์ „ํ˜ธ์šฐ์˜ ๋กœ๊ทธ๋ฅผ ๋‚จ๊น€
  • CORS ํ•„ํ„ฐ : ํ—ค๋” ์„ค์ • ํ›„ ๋‹ค์Œ ํ•„ํ„ฐ๋กœ ๋„˜๊น€

ํ•„ํ„ฐ ์ฒด์ธ์„ ๋„˜๊ธฐ์ง€ ์•Š์œผ๋ฉด ์š”์ฒญ์ด ์ค‘๋‹จ๋˜๊ณ , ์ปจํŠธ๋กค๋Ÿฌ์— ๋„๋‹ฌํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค.

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {

    // ์ „์ฒ˜๋ฆฌ ๋กœ์ง
    // ํ˜„์žฌ ์š”์ฒญ URI ๋กœ๊ทธ ์ถœ๋ ฅ. ๋””๋ฒ„๊น…์šฉ
    System.out.println("๐Ÿ”ฅ JwtFilter ์ง„์ž… : " + request.getRequestURI());

    // ๋‹ค์Œ ํ•„ํ„ฐ๋กœ ์ „๋‹ฌ (์—ฌ๊ธฐ์„œ ์•ˆ ๋„˜๊ธฐ๋ฉด ํ•„ํ„ฐ ์ฒด์ธ์ด ๋Š๊น€)
    chain.doFilter(request, response);

    // ํ›„์ฒ˜๋ฆฌ ๋กœ์ง
    System.out.println("ํ•„ํ„ฐ ์ข…๋ฃŒ");
}

ํ๋ฆ„ ๊ตฌ์กฐ

[์š”์ฒญ]
  โ†“
Filter1 โ†’ Filter2 โ†’ Filter3 โ†’ Controller
  โ†‘                        โ†‘
ํ›„์ฒ˜๋ฆฌ                   ํ›„์ฒ˜๋ฆฌ

๐Ÿค ํšŒ๊ณ 

2์ฐจ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ JWT(Json Web Token)๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋˜์—ˆ๊ณ , ์ด๋ฅผ ๋ณด๋‹ค ์ •ํ™•ํžˆ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๊ด€๋ จ ๊ฐœ๋…๊ณผ ๋™์ž‘ ๋ฐฉ์‹์„ ๊นŠ์ด ์žˆ๊ฒŒ ํ•™์Šตํ•˜์˜€๋‹ค.

stateless ์™€ stateful ์— ๋Œ€ํ•ด ์‚ด์ง ๋ดค๋Š”๋ฐ ๋งค๋ฒˆ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š”๊ฒŒ ๋” ์ข‹๋‚˜? ์‹ถ์€ ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. GPT์— ์งˆ๋ฌธํ•ด๋ณด์•˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด ๋‹ต์„ ๋ฐ›์•˜๋‹ค.

JWT๋ฅผ ๋งค๋ฒˆ ์ฃผ๊ณ  ๋ฐ›๋Š” ๊ฒƒ, ๊ดœ์ฐฎ์„๊นŒ??

์žฅ์  : ์„œ๋ฒ„ ๋ถ€๋‹ด์ด ์ ๋‹ค (Stateless ๊ตฌ์กฐ)

  • ์„œ๋ฒ„๊ฐ€ ์ƒํƒœ(session)๋ฅผ ๊ธฐ์–ตํ•˜์ง€ ์•Š์•„๋„ ๋˜๋ฏ€๋กœ ํ™•์žฅ์„ฑ์ด ์ข‹๋‹ค
  • ์„œ๋ฒ„ ์žฌ์‹œ์ž‘/๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑํ•ด๋„ ๋ณ„๋„ ์„ธ์…˜ ๋ณต์ œ ๋ถˆํ•„์š”
  • ์‚ฌ์šฉ์ž ์ˆ˜๊ฐ€ ๋งŽ์„์ˆ˜๋ก ๋ฉ”๋ชจ๋ฆฌ ๋ถ€๋‹ด ์ค„์–ด๋“ฆ

๋‹จ์  : ๋งค๋ฒˆ ์ •๋ณด๊ฐ€ ์ „๋‹ฌ๋˜๋‹ˆ ํฌ๊ธฐ/๋ณด์•ˆ ์ฃผ์˜

๋ฌธ์ œ์„ค๋ช…
๐Ÿ”น ๋„คํŠธ์›Œํฌ ๋น„์šฉJWT๋Š” ๋ณดํ†ต 1~2KB ํฌ๊ธฐ โ†’ ์š”์ฒญ์ด ๋งŽ์•„์ง€๋ฉด ๋„คํŠธ์›Œํฌ ๋‚ญ๋น„ ์šฐ๋ ค
๐Ÿ”น ๋ณด์•ˆ ์ด์Šˆํ† ํฐ ์•ˆ์— ์ธ์ฝ”๋”ฉ๋œ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ ์žˆ์Œ โ†’ ํƒˆ์ทจ ์‹œ ์œ„ํ—˜ (์•”ํ˜ธํ™” X, ์„œ๋ช…๋งŒ ํ•จ)
๐Ÿ”น ๋ฌดํšจํ™” ์–ด๋ ค์›€ํ•œ ๋ฒˆ ๋ฐœ๊ธ‰ํ•œ ํ† ํฐ์€ ์œ ํšจ์‹œ๊ฐ„ ๋™์•ˆ ์ทจ์†Œ๊ฐ€ ์–ด๋ ค์›€ (์„œ๋ฒ„๊ฐ€ ์ƒํƒœ๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ)

์ผ๋ฐ˜์ ์œผ๋กœ๋Š”?

์ƒํ™ฉ๊ถŒ์žฅ ๋ฐฉ์‹
๋ถ„์‚ฐ ์„œ๋ฒ„ / ํ™•์žฅ์„ฑ ์ค‘์š”JWT (stateless) ์œ ๋ฆฌ
๋ณด์•ˆ, ํ† ํฐ ์ทจ์†Œ ํ•„์š”์„ธ์…˜ ๊ธฐ๋ฐ˜ (stateful) ๋˜๋Š” ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ ๋ณ‘ํ–‰ ๊ถŒ์žฅ

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

profile
์นœ์• ํ•˜๋Š” ๊ฐœ๋ฐœ์ž

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