JSON Web Token
์ฌ์ฉ์ ์ธ์ฆ(Authentication)๊ณผ ๊ถํ ๋ถ์ฌ(Authorization)์ ์ฌ์ฉํ๋ ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ ๋ฐฉ์
์ฌ์ฉ์์ ๋ก๊ทธ์ธ ์ ๋ณด๋ฅผ ์์ ํ๊ฒ ๋ด์ ์๋ฒ - ํด๋ผ์ด์ธํธ ๊ฐ์ ์ ๋ฌํ๋ ์๋ช ๋ ํ ํฐ์ด๋ค.
์ธ ๋ถ๋ถ์ผ๋ก ๊ตฌ์ฑ๋ ๋ฌด์์ด
xxxxx.yyyyy.zzzzz
| ๋ถ๋ถ | ๋ด์ฉ | ์ค๋ช |
|---|---|---|
| Header | ํ ํฐ ํ์ ๊ณผ ์๊ณ ๋ฆฌ์ฆ | ์: { "alg": "HS256", "typ": "JWT" } |
| Payload | ์ฌ์ฉ์ ์ ๋ณด (Claims) | ์: userId, role, exp(๋ง๋ฃ์๊ฐ) |
| Signature | ์์กฐ ๋ฐฉ์ง์ฉ ์๋ช | ๋น๋ฐ ํค๋ก ์๋ช ํ์ฌ ์๋ณ์กฐ ๋ฐฉ์ง |
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJzdWIiOiAidXNlcjEiLCAicm9sZSI6ICJVU0VSIiwgImV4cCI6IDE3NTQwMDAwMDB9. XqVfNNjOt-y0IxqFe9fJexBJKrLdKK7-_a9UOi27_xg
{
"sub": "user1",
"role": "USER",
"exp": 1754000000
}
| ํค | ์๋ฏธ | ์์ ๊ฐ | ์ค๋ช |
|---|---|---|---|
sub | Subject (์ฃผ์ฒด) | "user1" | ๋ณดํต ์ฌ์ฉ์ ์๋ณ์ (์: user ID, ์ด๋ฉ์ผ ๋ฑ) |
role | ์ฌ์ฉ์ ๊ถํ | "USER" | ์ธ์ฆ๋ ์ฌ์ฉ์์ ๊ถํ (์: ADMIN, USER ๋ฑ) |
exp | Expiration (๋ง๋ฃ ์๊ฐ) | 1754000000 | ํ ํฐ ๋ง๋ฃ ์๊ฐ (Unix timestamp) |
JWT๋ base64๋ก ์ธ์ฝ๋ฉ๋๊ธฐ ๋๋ฌธ์, ์์ json์
eyJzdWIiOiAidXNlcjEiLCAicm9sZSI6ICJVU0VSIiwgImV4cCI6IDE3NTQwMDAwMDB9
๋ก ๋ณํ๋์ด JWT ์ค๊ฐ ๋ถ๋ถ์ผ๋ก ๋ค์ด๊ฐ๋ค.
Authorization: Bearer <JWT> ํค๋์ ํ ํฐ์ ๋ด์ ์ ์กstateless(๋ฌด์ํ) : ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์ ์ด์ ์์ฒญ ์ํ๋ฅผ ๊ธฐ์ตํ์ง ์๋ ๊ตฌ์กฐ
stateful(์ํ ์ ์ง ๋ฐฉ์) : ์๋ฒ๊ฐ ๋ก๊ทธ์ธํ ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํด ๋๊ณ ์ํ๋ฅผ ๊ธฐ์ตํ๋ ๊ตฌ์กฐ
| ์ํฉ | JWT ์ ํฉ ์ฌ๋ถ |
|---|---|
| ๋ชจ๋ฐ์ผ ์ฑ, SPA(React/Vue) ๋ก๊ทธ์ธ ์ฒ๋ฆฌ | ์ ํฉ |
| ์๋ฒ ๊ฐ ํต์ ์ธ์ฆ | ์ ํฉ |
| ๋ณด์์ด ๋ฏผ๊ฐํ๊ณ ๋ก๊ทธ์์์ด ์์ฃผ ํ์ํ ์น์ฌ์ดํธ | โ ๏ธ ์ธ์ ๋ฐฉ์์ด ๋์ ์ ์์ |
POST /login
โ ์๋ต: JWT ๋ฐ๊ธ
GET /myPage
Authorization: Bearer eyJhbGciOi...
โ ์๋ฒ๋ ํ ํฐ์ ๊ฒ์ฆํ๊ณ ๋ก๊ทธ์ธ๋ ์ฌ์ฉ์ ์ ๋ณด ์ฌ์ฉ
Spring Framework์์ ์ ๊ณตํ๋ ์๋ธ๋ฆฟ ํํฐ(Filter) ์ ์ถ์ ํด๋์ค
javax.servlet.Filter ๋ ํ ์์ฒญ์์ ์ฌ๋ฌ ๋ฒ ์คํ๋ ์ ์๋ ์ํ์ด ์๋ค.(์:ํฌ์๋ฉ)
OncePerRequestFilter๋ ํ ์์ฒญ์ ๋ฑ ํ ๋ฒ๋ง doFilterInternal() ๋ฉ์๋๊ฐ ์คํ๋๋๋ก ๋ณด์ฅํ๋ค.
์ฆ, ์ค๋ณต ์คํ์ ๋ฐฉ์งํ๋ฉด์ ํํฐ ๊ธฐ๋ฅ์ ๊ตฌํํ ์ ์๋๋ก ๋์์ฃผ๋ ํด๋์ค
๋ณดํต Spring Security์์ ์ธ์ฆ/์ธ๊ฐ ์ฒ๋ฆฌ๋ฅผ ์ํ JWT ํํฐ, ๋ก๊น ํํฐ ๋ฑ์ ์ฌ์ฉํ๋ค.
[์์ฒญ] โ [OncePerRequestFilter ๊ตฌํ์ฒด (์: JwtFilter)] โ [๋ค์ ํํฐ or ์ปจํธ๋กค๋ฌ]
์๋ฐ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ฌ๋ฌ ๊ฐ์ ํํฐ๋ฅผ ์์ฐจ์ ์ผ๋ก ์ฐ๊ฒฐํ์ฌ ์คํํ ์ ์๋๋ก ํด์ฃผ๋ ๊ฐ์ฒด์ด๋ค.
๋ณดํต doFilter() ๋ฉ์๋ ์์์ ๋ค์ ํํฐ ๋๋ ์๋ธ๋ฆฟ์ผ๋ก ์์ฒญ์ ๋๊ธธ ๋ ์ฌ์ฉํ๋ค. (์: Spring Security, Logging Filter, JWT Filter ๋ฑ)
chain.doFilter() ํธ์ถํํฐ ์ฒด์ธ์ ๋๊ธฐ์ง ์์ผ๋ฉด ์์ฒญ์ด ์ค๋จ๋๊ณ , ์ปจํธ๋กค๋ฌ์ ๋๋ฌํ์ง ์๊ฒ ๋๋ค.
@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๋ ๋ณดํต 1~2KB ํฌ๊ธฐ โ ์์ฒญ์ด ๋ง์์ง๋ฉด ๋คํธ์ํฌ ๋ญ๋น ์ฐ๋ ค |
| ๐น ๋ณด์ ์ด์ | ํ ํฐ ์์ ์ธ์ฝ๋ฉ๋ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ๋ด๊ฒจ ์์ โ ํ์ทจ ์ ์ํ (์ํธํ X, ์๋ช ๋ง ํจ) |
| ๐น ๋ฌดํจํ ์ด๋ ค์ | ํ ๋ฒ ๋ฐ๊ธํ ํ ํฐ์ ์ ํจ์๊ฐ ๋์ ์ทจ์๊ฐ ์ด๋ ค์ (์๋ฒ๊ฐ ์ํ๋ฅผ ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ) |
| ์ํฉ | ๊ถ์ฅ ๋ฐฉ์ |
|---|---|
| ๋ถ์ฐ ์๋ฒ / ํ์ฅ์ฑ ์ค์ | JWT (stateless) ์ ๋ฆฌ |
| ๋ณด์, ํ ํฐ ์ทจ์ ํ์ | ์ธ์ ๊ธฐ๋ฐ (stateful) ๋๋ ๋ฆฌํ๋ ์ ํ ํฐ ๋ณํ ๊ถ์ฅ |
์ฆ, ์ ๋ฆฌํ์๋ฉด
JWT๋ฅผ ๋งค๋ฒ ์ฃผ๊ณ ๋ฐ๋ ๊ฒ์ ํ์ฅ์ฑ๊ณผ ์ ์ง๋ณด์ ์ธก๋ฉด์์ ์ฅ์ ์ด ์์ง๋ง,
๋ณด์๊ณผ ์ฑ๋ฅ ์ธก๋ฉด์์๋ ์ค๊ณ์ ์ฃผ์๊ฐ ํ์ํ๋ค.
๊ทธ๋์ JWT + Refresh Token ์กฐํฉ์ด ์์ฃผ ์ฐ์ธ๋ค.