DevLog ๐ถ
[Web] JWT๋ฅผ ํตํ ์ธ์ฆ ๊ณผ์ ์์๋ณด๊ธฐ ๋ณธ๋ฌธ
๐ฑ ๋ค์ด๊ฐ๊ธฐ ์
๋ง์ฐฌ๊ฐ์ง๋ก ํ ์ฝํก์์ ์งํํ๋ ๋ฐํ ์๋ฃ๋ฅผ ๋ฐํ์ผ๋ก ๊ธ์ ์์ฑํ์์ต๋๋ค!
์ธ์ฆ๊ณผ ์ธ๊ฐ, ์ฟ ํค / ์ธ์ ๋ฐฉ์์ ๋ํด์๋ ์ด์ ํฌ์คํ ์์ ์์ฑํ์์ต๋๋ค.
4. ํจ์จ์ ์ผ๋ก ์ธ์ฆํ๊ธฐ
์ง๋ ํฌ์คํ ์์๋ ์ธ์ ์ ํตํด์ ์์ ํ๊ฒ ์ธ์ฆํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์๋ค.
ํ์ง๋ง, ์ธ์ ๋ฐฉ์์ ๊ฐ์ฅ ํฐ ๋ฌธ์ ์ ์ ์๋ฒ๋, ํด๋ผ์ด์ธํธ๋, ๊ทธ๋ฆฌ๊ณ ์ธ์ ์คํ ๋ฆฌ์ง๊น์ง ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋ ์ฃผ์ฒด๊ฐ ๋๋ฌด ๋ค์ํ๋ค๋ ๊ฒ์ด๋ค. ์ด๋ฌํ ๋ฌธ์ ์ ์ ํด๊ฒฐํ๊ธฐ ์ํด์, ์ํ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ ๋ฐ๋ก ๋์ง ์๊ณ ์์ฒญ๊ณผ ์๋ต ๋ด๋ถ์์ ์ฒ๋ฆฌํ๋ ๊ฒ์ด ํ ํฐ ์ธ์ฆ ๋ฐฉ์์ด๋ค.
+) ์ธ์ ๊ธฐ๋ฐ ์ธ์ฆ ๋ฐฉ์์์ ํ ํฐ ์ธ์ฆ ๋ฐฉ์์ด ๋์จ ์ด์ ์ค์ ํ๋๊ฐ DB์ ์ธ์ฆ ์ ๋ณด๋ฅผ ์ ์ฅํ์ง ์์์ ์๋ฒ์ ๋ํ ๋ถํ๋ฅผ ์ค์ด๋ ๊ฒ๋ ์๋ค๊ณ ๋ง์ด๋ค ๋งํ๋ค. ์ํธํ๋ ์ธ์ฆ ์ ๋ณด๋ฅผ ํด๋ผ์ด์ธํธ๊ฐ ๊ด๋ฆฌํจ์ผ๋ก์ ๋ถํ๋ฅผ ์ค์ธ๋ค๊ณ ๋ ํ์ง๋ง... ์ฌ์ค ๋ณด์ ์ธก๋ฉด์ผ๋ก ๋ณด๋ฉด JWT ์ญ์ DB๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค ๋ณด๋๊น ์ด๋ฐ ๊ด์ ์์๋ ํฌ๊ฒ ์ข์์ง ์ ๋ชจ๋ฅด๊ฒ ๋ค. (๊ฐ์ธ์ ์ธ ์๊ฒฌ)
ํ ํฐ ๋ฐฉ์์ผ๋ก๋ ๋ํ์ ์ผ๋ก 'JWT (Json Web Token)'๊ฐ ์กด์ฌํ๋ค.
JWT๋ ์ ๋ณด๋ฅผ Json ๊ฐ์ฒด๋ฅผ ํตํด ์์ ํ๊ฒ ์ ์กํ๊ธฐ ์ํ ๊ฐ๊ฒฐํ๊ณ , ๋ ๋ฆฝ์ ์ธ ๋ฐฉ๋ฒ์ ์ ์ํ๋ ๊ฐ๋ฐฉํ ํ์ค์ด๋ค. (RFC 7519)
๊ธฐ๋ณธ์ ์ผ๋ก HMAC ์๊ณ ๋ฆฌ์ฆ์ ํตํด ์ํธํ๊ฐ ๋์ด ์์ผ๋ฉฐ, RSA๋ ECDSA๋ฅผ ์ฌ์ฉํ๋ ๊ณต๊ฐ-๊ฐ์ธํค ์์ ํตํด ์๋ช ํ ์ ์๋ค.
JWT๋ ํฌ๊ฒ ํค๋, ํ์ด๋ก๋, ๊ทธ๋ฆฌ๊ณ ์๊ทธ๋์ฒ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.
๐ฌ Header
ํค๋๋ ์ผ๋ฐ์ ์ผ๋ก ํ ํฐ ์ ํ๊ณผ ์๋ช ์๊ณ ๋ฆฌ์ฆ 2๊ฐ์ง๊ฐ ํฌํจ๋์ด ์๋ค.
{
"alg": "HS256",
"typ": "JWT"
}
๋ง์ฝ ์ด๋ฐ ์์ผ๋ก ๊ตฌ์ฑ๋์ด ์๋ค๋ฉด, ์ด๋ ํ์ฌ ํ์ ์ JWT, ์๋ช ์๊ณ ๋ฆฌ์ฆ์ผ๋ก HS256์ ์ฌ์ฉํ์์ ๋ํ๋ธ๋ค.
์ด ์ ๋ณด๋ฅผ Base64๋ก ์ธ์ฝ๋ฉํ๊ฒ ๋๋ฉด JWT์ ํค๋ ๋ถ๋ถ์ด ์์ฑ๋๋ค.
๐ฌ Payload
payload์ claim ์ ๋ณด๊ฐ ํฌํจ๋๋ฉฐ, claim์ entity์ ๋ํ ๋ด์ฉ์ด ๋ค์ด๊ฐ๋ค. (์ฌ์ฉ์์ ๋ํ ์ ๋ณด)
์ธ์ฆ์ ํ์ํ ์ ๋ณด๊ฐ ๋ณดํต ์ด๊ณณ์ ๋ค์ด๊ฐ์ง๋ง, ๋ฏผ๊ฐํ ์ ๋ณด๋ ๋ฃ์ง ์๋ ๊ฒ์ด ์ข๋ค.
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
๋ง์ฐฌ๊ฐ์ง๋ก ์์ ๋ํ ์ ๋ณด๋ฅผ base64๋ก ์ธ์ฝ๋ฉํ๋ฉด payload์ ๋ํ ์ ๋ณด๊ฐ ๋ค์ด๊ฐ๋ค.
๐ฌ Signature
์ธ์ฝ๋ฉ๋ ํค๋ ๋ฐ ์ธ์ฝ๋ฉ๋ ํ์ด๋ก๋, secret (๋น๋ฐ ํค ์ ๋ณด), ํค๋์ ์ง์ ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ์ฌ ์๋ช ํ ์ ์๋ค.
๋ง์ฝ HMAC SHA256 ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ค๋ฉด ์๋์ ๊ฐ์ด ์๋ช ์ด ๊ฐ๋ฅํ๋ค.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
์๊ทธ๋์ฒ ์ ๋ณด๋ ๋์ค์ ๋ณ๊ฒฝ๋์ง ์์๋์ง ํ์ธํ๋๋ฐ ์ฌ์ฉ๋๋ฉฐ, ๊ฐ์ธํค๋ก ์๋ช ๋ ํ ํฐ์ด๋ผ๋ฉด JWT์ ๋ฐ์ ์๊ฐ ๋ณธ์ธ์ด ๋ง๋์ง ํ์ธํ๋๋ฐ๋ ์ฌ์ฉ๋๋ค.
๊ทธ๋์ ๊ฒฐ๊ณผ์ ์ผ๋ก JWT๋ .์ผ๋ก ๊ตฌ๋ถ๋ 3๊ฐ์ Base64๋ก ์ธ์ฝ๋ฉ๋ ๋ฌธ์์ด์ ํฉ์ผ๋ก ์ด๋ฃจ์ด์ ธ ์๋ค.
๋ณดํต ์ฐ๋ฆฌ๊ฐ ์ฝ๋์์ ํ์ฉํ ๋์๋ 'Bearer' ๋ผ๋ prefix๋ฅผ ์ฌ์ฉํ์ฌ Authorization ํค๋์ ๋ฃ๋ ๊ฒ์ด ์ผ๋ฐ์ ์ด๋ค.
Authorization: Bearer <token>
์ฐธ๊ณ ๋ก, ๋์ค์ ์ค์ ํด๋ผ์ด์ธํธ์ ํต์ ํ ๋ CORS ๋ฌธ์ ๋ฅผ ๊ฒช์ ์ ์๊ธฐ ๋๋ฌธ์ ์๋ฒ์ธก์์ exposedHeader ๊ฐ์ผ๋ก Authroization ํค๋๋ฅผ ํ์ฉํด์ค์ผ ํ๋ค. (์ด๊ฑฐ๋ ๋ค์์ ํฌ์คํ ์ ๋ฐ๋ก ํด๋ณด๊ฒ ๋ค ใ ใ )
์ค์ ๋ก ํ์ต ํ ์คํธ์์ ์ดํด๋ณด์๋ ํ ํฐ ์์ฑ ์ฝ๋๋ฅผ ํ์ธํด๋ณด์.
public String createToken(String payload) {
Claims claims = Jwts.claims().setSubject(payload);
Date now = new Date();
Date validity = new Date(now.getTime() + validityInMilliseconds);
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(validity)
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
}
์ฝ๋๋ฅผ ๊ฐ๊ฐ ๋ถ์ํด๋ณด๋ฉด ์์ ๊ฐ์ด claim์ ํตํ ์ฌ์ฉ์ ์ ๋ณด ์ง์ ๋ฐ ๋ง๋ฃ ์๊ฐ, ๊ทธ๋ฆฌ๊ณ ์ํฌ๋ฆฟํค๋ฅผ ํตํ ์ํธํ๋ฅผ ํ๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ , ํด๋น ํ ํฐ์ ๋ค์ ํด๋ ํ ๋๋ ์๋ฒ ๋ด์์ ๊ด๋ฆฌํ๋ ์ํฌ๋ฆฟํค๋ฅผ ํตํด์ ํด๋ ํ๋ค.
public String getPayload(String token) {
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
๐ก ์ฌ๊ธฐ์ ํ ๊ฐ์ง ์ฃผ๋ชฉํ ์ ์ด ์๋ค.
parseClaimsJws()๋ผ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ณ ์๋ ๊ฑธ ๋ณผ ์ ์๋๋ฐ, ์ด๊ฑฐ ๋์ ์ parseClaimsJwt()๋ฅผ ์ฌ์ฉํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
์ด๋, ์ฐ๋ฆฌ๊ฐ ์ฒ์์ ํ ํฐ์ ์์ฑํ ๋ signWith์ ํตํด์ ์๋ช ์ ์งํํ๊ธฐ ๋๋ฌธ์ ๋ณตํธํ ์์๋ ์๋ช ์ ๋ํ ๊ฒ์ฆ์ ์งํํด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค. (Jwt()์ ๊ฒฝ์ฐ ์๋ช ๊ฒ์ฆ ์์ด ๋จ์ํ ํค๋์ ํด๋ ์๋ง ์ถ์ถํจ)
parseClaimsJwt()์ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ํ ํฐ ์์ฑ ์์ signWith์ ํตํด์ ์๋ช ์ ๋ํ ์ ๋ณด๋ฅผ ๋๊ฒจ์ฃผ์ง ์์ผ๋ฉด ๋๋ค.
๐ฌ ๋์ ๋ฐฉ์ ์์๋ณด๊ธฐ
ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ ๋ฐฉ์์ ์๋์ ๊ฐ์ด ๋์ํ ์ ์๋ค.
ํด๋ผ์ด์ธํธ์๊ฒ ์์ฑ๋ ํ ํฐ์ ๋ด๋ ค์ฃผ๋ ๋ฐฉ์์ ๋ค์ํ๋ฐ, ๋๋ ์์ ๊ฐ์ด Authorization ํค๋์ ๋ด์์ ๋ด๋ ค์คฌ๋ค.
ํด๋ผ์ด์ธํธ๋ ํด๋น ๊ฐ์ ๋ฐ์์ ๋ค์ ์์ฒญ ์ Authorization ํค๋์ JWT ์ ๋ณด๋ฅผ ํจ๊ป ๋ฃ์ด์ ๋ณด๋ด๋๋ฐ, ์๋ฒ๋ ํด๋น ํค๋ฅผ ์์ฑํ ๋ ์ฌ์ฉํ์๋ ์ํฌ๋ฆฟํค ์ ๋ณด๋ฅผ ํ์ฉํ์ฌ ๋ค์ ๋์ฝ๋ฉ ํ์ ๋ด๋ถ์ ์๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ์ธ์ฆ์ ์งํํ๋ค.
๐ฌ ์ฅ์ / ๋จ์
ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ ๋ฐฉ์์ ๊ฒฝ์ฐ ์๋ฒ ์ธก์์ ๋ฐ๋ก ์ ์ฅํ ํ์๊ฐ ์์ผ๋ฉฐ, ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ํด ํค๋ ๊ฐ์ ํจ๊ป ํฌํจ์์ผ ๋ณด๋ด์ฃผ๋ฉด ๋๋ค.
๋ํ, MSA ๊ฐ์ ๊ตฌ์กฐ๋ ์๋ฒ๊ฐ ์ฌ๋ฌ ๋์ธ ์ํฉ์ด๋ผ๋ฉด ๊ฐ์ ํ ํฐ์ ํตํด ์ฌ๋ฌ ์๋ฒ์์ ์ธ์ฆ์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ๋ ํจ์จ์ ์ด๋ค.
(์ด์ ์ ๋ดค๋ ์ธ์ ์ธ์ฆ ๋ฐฉ์์์๋ ์ธ์ ์คํ ๋ฆฌ์ง ๊ฐ์ ๊ฒ์ ๋์์๋๋ฐ, ์ด๋ฐ ์ ์์๋ ์ข๋ค ใ ใ )
ํ์ง๋ง, JWT์ ๊ฒฝ์ฐ ํ์ทจ ๋นํ๋ค๋ฉด ํด๋น ์ฌ์ฉ์์ ๊ถํ์ ๊ทธ๋๋ก ๊ฐ์ง๊ฒ ๋๋ค.
ํ์ทจ๋นํ JWT์ ๊ฒฝ์ฐ ์ ํจ ๊ธฐ๊ฐ์ด ์ง๋๊ธฐ ์ ๊น์ง๋ ๊ฐ์ ๋ก ๋ง๋ฃ์ํฌ ์ ์๊ธฐ ๋๋ฌธ์, ์ ๋ณด๋ฅผ ๋ฐ๋ก ์ ๊ฑฐํ ์ ์๋ ์ธ์ ์ ๋นํด์๋ ๋ณด์์ ์ธก๋ฉด์์๋ ๋จ์ด์ง๋ค๊ณ ๋ณผ ์ ์๋ค. (๋ฌผ๋ก , ํด๋น ํ ํฐ์ claim ์ ๋ณด๊ฐ ์ ์ฑ ์ฌ์ฉ์์์ ํ์คํ๊ฒ ๋ํ๋ผ ์ ์๋ค๋ฉด, ํด๋น ์ฌ์ฉ์์ ์์ฒญ์ ์ฐจ๋จํ๋ ํํ๋ก๋ ๋ง๋ค ์ ์์ ๊ฒ ๊ฐ๋ค.) ๊ทธ๋์ ์ํ ๊ฐ์ ๋ณด์์ด ์ค์ํ ์์คํ ์์๋ ์ธ์ ์ ๋ง์ด ์ฌ์ฉํ๋ ๊ฒ์ผ๋ก ์๊ณ ์๋ค. (๋ํผ์ )
๐ฌ Refresh Token
๋ณดํต ํ์ทจ ๋ฌธ์ ๋ก ์ธํด์ JWT (์ด์ ๋ 'access token'์ด๋ผ๊ณ ๋ถ๋ฅด๊ฒ ๋ค.)์ ์ ํจ ๊ธฐ๊ฐ์ ์งง๊ฒ ๊ฐ์ ธ๊ฐ๋ ํธ์ด๋ฉฐ (30๋ถ ์ ๋), ๊ธฐํ์ด ์งง์ผ๋ฉด ์์ฒญ์ ๋ํด์ ์๋กญ๊ฒ ๋ฐ๊ธ๋ฐ์์ผ ํ๋ ํ์๊ฐ ๋์ด๋๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด 'refresh token'์ด๋ผ๋ ๊ฒ์ ๋ฐ๋ก ๋๊ธฐ๋ ํ๋ค.
access token์ ๋ํ ์ฌ๋ฐ๊ธ ๊ธฐ๋ฅ์ ์ฑ ์์ง๋ token์ด๋ฉฐ, ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ฒ์ ์ ์ฅํ ์ ์๊ณ (์ธ์ ์ ์ ์ฅํ๊ฑฐ๋ ์ฟ ํค์ ์ ์ฅํ๋ ๋ฐฉ๋ฒ๋ ์์ง๋ง, in-memory db์ ์ ์ฅํ๋ ๊ฒ์ด ์ผ๋ฐ์ ), ํ์ทจ๋ฅผ ๋นํ๋๋ผ๋ ํด๋น ์ฌ์ฉ์์ refresh token์ ๊ฐ์ ๋ก ์ ๊ฑฐํ์ฌ ๋ณด์์ ๋ํด์๋ ์์ ์ฑ์ด ๋์ ํ ํฐ์ด๋ค.
๋ณดํต refresh token์ ๊ฒฝ์ฐ ์ ํจ ๊ธฐ๊ฐ์ ์ผ์ฃผ์ผ~์ด์ฃผ์ผ ์ ๋๋ก ๋ง๋ค์ด๋๋ค.
์ฌ์ค ์ด์ ๋ํด ์ด๋ป๊ฒ ํ์ฉํ๋์ง๋ ๊ฐ๋ฐ์์ ๋ฐ๋ผ์ ๋ค๋ฅด์ง๋ง, ๋ณดํต ์ด๋ฐ ๋ฐฉ์์ ๋ง์ด ์ฌ์ฉํ๋ค. ์์์ ์์ฑํ ๊ทธ๋ฆผ๊ณผ ์ด์ด์ง๋ค๊ณ ์๊ฐํ์.
์ฌ๊ธฐ์ ๋ฐ์ ํ ํฐ ์ ๋ณด์ ๋ฐ๋ผ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ์คํ ์ด ๋๋์ด์ง๋๋ฐ, ๋ณดํต ์๋์ ๊ฐ์ ์ผ์ด์ค๋ค๋ก ๋๋๋ค.
๋ฌผ๋ก ์ฌ๊ธฐ์ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํด๋ ๋ฌด๋ฐฉํ๋ค.
๋ก์ง์ด ์๋นํ ๋ณต์กํด์ก์ง๋ง, access token์ ๋จ์ ์ ๊ทธ๋๋ง ๋ณด์ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋ง์ด ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
์งง์ access token์ ์ ํจ์๊ฐ์ ๋์ฒํ๊ธฐ ์ํ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก sliding session์ด๋ผ๋ ์น๊ตฌ๋ ์๋ค.
์ฌ์ฉ์๊ฐ ๊ณ์ํด์ ์๋น์ค๋ฅผ ์ด์ฉํ๊ณ ์๋ค๋ฉด (JS์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ก ๊ฐ์ง) access token์ด ๋ง๋ฃ๋๊ธฐ ์ ์ ์๋ก์ด access token์ ๋ฐ๊ธ๋ฐ์ ์๋์ผ๋ก ๊ฐฑ์ ํ ํ ํฐ์ ๋ฐ์์ค๋ ๊ฒ์ด๋ค. ์ด๊ฑด ๊ตฌํํด๋ณธ ์ ์ด ์์ด์ ์ ๋ชจ๋ฅด๊ฒ ์ง๋ง... ์๋ฌด๋๋ ํด๋ผ์ด์ธํธ ์ธก์์ ๊ณ์ ํ์ธํด์ผ ํ ๊ฒ ๊ฐ๋ค.
'โ๏ธ > CS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[MySQL] ํธ๋์ญ์ ๊ฒฉ๋ฆฌ ์์ค์ ์ฟผ๋ฆฌ๋ฅผ ํตํด ์ง์ ํ ์คํธํด๋ณด๊ธฐ (0) | 2023.06.21 |
---|---|
[Web] ์ธ์ฆ๊ณผ ์ธ๊ฐ๋? - ์ฟ ํค์ ์ธ์ ์ ๋ํด์ ์์๋ณด์! (2) | 2023.05.03 |
[HTTP] GET vs POST, GET์ body ๊ฐ์ ๊ฐ์ง๋ฉด ์ ๋ ๊น? (4) | 2023.04.19 |
[MSA] MicroService, SoA (0) | 2022.10.20 |