๐ JSON Web Token (JWT): ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ ์์คํ ๊ตฌ์ถ ๐

์๋ ํ์ธ์, ์ฌ๋ฌ๋ถ! ์ค๋์ ์ ๋ง ํฅ๋ฏธ์ง์งํ ์ฃผ์ ๋ก ์ฌ๋ฌ๋ถ๊ณผ ํจ๊ป ์๊ฐ์ ๋ณด๋ด๋ ค๊ณ ํด์. ๋ฐ๋ก JSON Web Token(JWT)์ ๋ํด ์์๋ณด๊ณ , ์ด๋ฅผ ํ์ฉํ ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ ์์คํ ์ ์ด๋ป๊ฒ ๊ตฌ์ถํ๋์ง ์ดํด๋ณผ ๊ฑฐ์์. ๐
์ฌ๋ฌ๋ถ, ํน์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉํ๋ฉด์ ๋ก๊ทธ์ธ์ ํด๋ณธ ์ ์๋์? ๋ฌผ๋ก ์๊ฒ ์ฃ ! ๊ทธ๋ฐ๋ฐ ๊ทธ ๋ค์์ ์ด๋ค ๋ง๋ฒ ๊ฐ์ ์ผ์ด ๋ฒ์ด์ง๊ณ ์๋์ง ๊ถ๊ธํ์ง ์์ผ์ จ๋์? ์ค๋ ์ฐ๋ฆฌ๋ ๊ทธ ๋ง๋ฒ์ ๋น๋ฐ์ ํํค์ณ๋ณผ ๊ฑฐ์์. ํนํ JWT๋ผ๋ ๊ฐ๋ ฅํ ๋๊ตฌ๋ฅผ ์ฌ์ฉํด์ ๋ง์ด์ฃ ! ๐
์ด ๊ธ์ ํตํด ์ฌ๋ฌ๋ถ์ JWT๊ฐ ๋ฌด์์ธ์ง, ์ด๋ป๊ฒ ์๋ํ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ ๋ง์ ๊ฐ๋ฐ์๋ค์ด ์ด๋ฅผ ์ ํธํ๋์ง ์ดํดํ๊ฒ ๋ ๊ฑฐ์์. ๋ ๋์๊ฐ ์ค์ ๋ก JWT๋ฅผ ํ์ฉํ ์ธ์ฆ ์์คํ ์ ์ด๋ป๊ฒ ๊ตฌ์ถํ๋์ง ๋จ๊ณ๋ณ๋ก ์์๋ณผ ๊ฑฐ์์. ๋ง์น ๋ ๊ณ ๋ธ๋ก์ ์กฐ๋ฆฝํ๋ฏ์ด, ํ๋ํ๋ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐฐ์๋๊ฐ ๊ฑฐ์์!
๊ทธ๋ฆฌ๊ณ ์ ๊น! ์ฌ๋ฌ๋ถ, ํน์ ์ฌ๋ฅ๋ท(https://www.jaenung.net)์ด๋ผ๋ ์ฌ์ดํธ๋ฅผ ๋ค์ด๋ณด์ จ๋์? ์ด๊ณณ์ ๋ค์ํ ์ฌ๋ฅ์ ๊ฑฐ๋ํ ์ ์๋ ํ๋ซํผ์ธ๋ฐ์, ์ฐ๋ฆฌ๊ฐ ์ค๋ ๋ฐฐ์ธ JWT์ ๊ฐ์ ๊ธฐ์ ์ด ์ด๋ฐ ํ๋ซํผ์ ๋ณด์์ ์ฑ ์์ง๊ณ ์๋ต๋๋ค. ์ฌ๋ฅ๋ท์์ ์์ ํ๊ฒ ๊ฑฐ๋ํ ์ ์๋ ์ด์ ์ค ํ๋๊ฐ ๋ฐ๋ก ์ด๋ฐ ์ฒจ๋จ ์ธ์ฆ ๊ธฐ์ ๋๋ถ์ด์์! ๐จโ๐ป๐ฉโ๐ป
์, ์ด์ ์ ๋ง ํฅ๋ฏธ์ง์งํ JWT์ ์ธ๊ณ๋ก ๋น ์ ธ๋ณผ ์ค๋น ๋์ จ๋์? ๊ทธ๋ผ ์ถ๋ฐํด๋ณผ๊น์? Let's JWT! ๐
๐งฉ JWT๋ ๋ฌด์์ธ๊ฐ? - ํ ํฐ์ ๋ง๋ฒ์ ํ๋ค
์, ์ฌ๋ฌ๋ถ! JWT๋ผ๋ ๋จ์ด๋ฅผ ์ฒ์ ๋ค์ด๋ณด์ จ๋ค๋ฉด, ๊ฑฑ์ ๋ง์ธ์. ์ฐ๋ฆฌ ํจ๊ป ์ด ์ ๋น๋ก์ด ์ฝ์์ ๋น๋ฐ์ ํ๋์ฉ ํ์ด๋ณผ ๊ฑฐ์์. JWT๋ JSON Web Token์ ์ฝ์์ธ๋ฐ์, ์ด๋ฆ์์ ์ ์ ์๋ฏ์ด JSON ํํ์ ๋ฐ์ดํฐ๋ฅผ ์น์์ ์ฌ์ฉํ๋ ํ ํฐ์ด์์. ๐ญ
JWT๋ ์ ๋ณด๋ฅผ ์์ ํ๊ฒ ์ ๋ฌํ๊ธฐ ์ํ ๊ฐ๋ฐฉํ ํ์ค(RFC 7519)์ด์์. ์ฝ๊ฒ ๋งํด, ๋๊ตฐ๊ฐ์๊ฒ ๋น๋ฐ ๋ฉ์์ง๋ฅผ ์ ๋ฌํ ๋ ์ฌ์ฉํ๋ ํน๋ณํ ๋ดํฌ๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ์. ์ด ๋ดํฌ๋ ๋๊ตฌ๋ ๋ณผ ์ ์์ง๋ง, ๊ทธ ์์ ๋ด์ฉ์ ํน๋ณํ ์ด์ ๊ฐ ์์ด์ผ๋ง ์ฝ์ ์ ์์ฃ .
JWT์ ๊ตฌ์กฐ๋ ํฌ๊ฒ ์ธ ๋ถ๋ถ์ผ๋ก ๋๋์ด์:
- ํค๋ (Header): ํ ํฐ์ ํ์ ๊ณผ ํด์ ์๊ณ ๋ฆฌ์ฆ ์ ๋ณด๋ฅผ ๋ด๊ณ ์์ด์.
- ํ์ด๋ก๋ (Payload): ์ค์ ๋ก ์ ๋ฌํ๊ณ ์ ํ๋ ์ ๋ณด(ํด๋ ์)๊ฐ ๋ค์ด์์ด์.
- ์๋ช (Signature): ํ ํฐ์ด ์ ํจํ์ง ํ์ธํ ์ ์๋ ์๋ช ์ด ๋ค์ด์์ด์.
์ด ์ธ ๋ถ๋ถ์ ๊ฐ๊ฐ Base64Url๋ก ์ธ์ฝ๋ฉ๋์ด ์ (.)์ผ๋ก ๊ตฌ๋ถ๋ผ์. ๊ทธ๋์ JWT๋ฅผ ๋ณด๋ฉด ์ด๋ฐ ํํ๋ฅผ ๋ ๊ฒ ๋ฉ๋๋ค:
xxxxx.yyyyy.zzzzz
์ฌ๊ธฐ์ xxxxx๋ ํค๋, yyyyy๋ ํ์ด๋ก๋, zzzzz๋ ์๋ช ์ ๋ํ๋ด์. ๋ง์น ๋น๋ฐ ์ํธ ๊ฐ์ง ์๋์? ๐
๐ ์ฌ๋ฏธ์๋ ์ฌ์ค: JWT๋ ๋ง์น ๋์งํธ ์ธ๊ณ์ ์ฌ๊ถ๊ณผ ๊ฐ์์! ์ฌ๊ถ์๋ ์ฐ๋ฆฌ์ ์ ์ ์ ๋ณด๊ฐ ๋ด๊ฒจ ์๊ณ , ๊ทธ ์ ๋ณด์ ์ง์๋ฅผ ํ์ธํ ์ ์๋ ํน๋ณํ ํ์(์๋ช )๊ฐ ์์ฃ . JWT๋ ๋ง์ฐฌ๊ฐ์ง์์. ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ์์ ํ๊ฒ ๋ด์ ์ ๋ฌํ๊ณ , ๊ทธ ์ ๋ณด๊ฐ ๋ณ์กฐ๋์ง ์์์์ ์ฆ๋ช ํ ์ ์๋ต๋๋ค.
JWT์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ ๋ฐ๋ก ์ํ๋ฅผ ์ ์ฅํ์ง ์๋๋ค(Stateless)๋ ๊ฑฐ์์. ์ด๊ฒ ๋ฌด์จ ๋ง์ด๋๊ณ ์? ์ฝ๊ฒ ์ค๋ช ํด๋๋ฆด๊ฒ์!
์ ํต์ ์ธ ์ธ์ ๊ธฐ๋ฐ ์ธ์ฆ์์๋ ์๋ฒ๊ฐ ์ฌ์ฉ์์ ๋ก๊ทธ์ธ ์ํ๋ฅผ ๊ณ์ ๊ธฐ์ตํ๊ณ ์์ด์ผ ํ์ด์. ๋ง์น ๋์๊ด์์ ๋๊ฐ ์ด๋ค ์ฑ ์ ๋น๋ ค๊ฐ๋์ง ๊ณ์ ๊ธฐ๋กํ๊ณ ์๋ ๊ฒ์ฒ๋ผ์. ํ์ง๋ง JWT๋ฅผ ์ฌ์ฉํ๋ฉด, ์๋ฒ๋ ์ด๋ฐ ์ํ๋ฅผ ๊ธฐ์ตํ ํ์๊ฐ ์์ด์. ๋์ ์ฌ์ฉ์๊ฐ ์์ ์ ์ ๋ถ์ฆ(JWT)์ ๊ฐ์ง๊ณ ๋ค๋๋ฉด์, ํ์ํ ๋๋ง๋ค ๋ณด์ฌ์ฃผ๋ ๋ฐฉ์์ด์ฃ .
์ด๋ฐ ํน์ฑ ๋๋ฌธ์ JWT๋ ํนํ ๋ถ์ฐ ์์คํ ์ด๋ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ์์ ๋งค์ฐ ์ ์ฉํด์. ์ฌ๋ฌ ์๋ฒ๋ ์๋น์ค ๊ฐ์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฝ๊ฒ ๊ณต์ ํ ์ ์๊ธฐ ๋๋ฌธ์ด์ฃ . ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์์๋ ์ด๋ฐ ํน์ฑ์ ํ์ฉํ๋ฉด, ๋ค์ํ ์๋น์ค ๊ฐ์ ์ฌ์ฉ์ ์ธ์ฆ์ ์ํํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ต๋๋ค.
์ด ๊ทธ๋ฆผ์ ๋ณด๋ฉด JWT์ ๊ตฌ์กฐ๋ฅผ ํ๋์ ์ดํดํ ์ ์์ฃ ? ํค๋, ํ์ด๋ก๋, ์๋ช ์ด ์ (.)์ผ๋ก ๊ตฌ๋ถ๋์ด ์๊ณ , ๊ฐ๊ฐ์ ๋ถ๋ถ์ด Base64Url๋ก ์ธ์ฝ๋ฉ๋์ด ์์ด์. ์ด๋ ๊ฒ ๋ง๋ค์ด์ง JWT๋ ๋ง์น ๋น๋ฐ ์ด์ ์ฒ๋ผ ์ฌ์ฉ์์ ์ ์์ ์ฆ๋ช ํ๋ ๋ฐ ์ฌ์ฉ๋ฉ๋๋ค.
์, ์ด์ JWT๊ฐ ๋ญ์ง ๋๋ต์ ์ผ๋ก ๊ฐ์ด ์ค์๋์? ๐ ๋ค์์ผ๋ก ์ฐ๋ฆฌ๋ ์ด JWT๋ฅผ ์ด๋ป๊ฒ ์ค์ ๋ก ์ฌ์ฉํ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ ์ด๋ ๊ฒ ๋ง์ ๊ฐ๋ฐ์๋ค์ด JWT๋ฅผ ์ ํธํ๋์ง ์์ธํ ์์๋ณผ ๊ฑฐ์์. ์ค๋น๋์ จ๋์? ๋ ๊น์ด ๋ค์ด๊ฐ ๋ด ์๋ค!
๐ JWT์ ์๋ ์๋ฆฌ - ๋์งํธ ์ธ๊ณ์ ์ ๋ถ์ฆ
์, ์ด์ JWT๊ฐ ์ด๋ป๊ฒ ์๋ํ๋์ง ์์ธํ ์ดํด๋ณผ ์๊ฐ์ด์์! ๐ต๏ธโโ๏ธ JWT์ ์๋ ์๋ฆฌ๋ฅผ ์ดํดํ๋ฉด, ๋ง์น ๋์งํธ ์ธ๊ณ์ ๋น๋ฐ ์์์ด ๋ ๊ฒ ๊ฐ์ ๊ธฐ๋ถ์ด ๋ค ๊ฑฐ์์. ์๋๊ณ ์? JWT๋ ๋ง์น ์ฒฉ๋ณด ์ํ์ ๋์ค๋ ๋น๋ฐ ์ํธ์ ๊ฐ๊ฑฐ๋ ์!
JWT์ ์๋ ์๋ฆฌ๋ ํฌ๊ฒ ๋ ๋จ๊ณ๋ก ๋๋ ์ ์์ด์: ํ ํฐ ์์ฑ๊ณผ ํ ํฐ ๊ฒ์ฆ. ๊ฐ ๋จ๊ณ๋ฅผ ์์ธํ ์ดํด๋ณผ๊น์?
1. ํ ํฐ ์์ฑ ๋จ๊ณ ๐ญ
์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธ์ ํ๋ฉด, ์๋ฒ๋ JWT๋ฅผ ์์ฑํด์. ์ด ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ์์:
- ํค๋ ์์ฑ: ํ ํฐ์ ํ์ (JWT)๊ณผ ์ฌ์ฉํ ํด์ ์๊ณ ๋ฆฌ์ฆ(๋ณดํต HMAC SHA256 ๋๋ RSA)์ ์ง์ ํด์.
- ํ์ด๋ก๋ ์์ฑ: ์ฌ์ฉ์ ID, ์ด๋ฆ, ๊ถํ ๋ฑ์ ์ ๋ณด(ํด๋ ์)๋ฅผ ํฌํจํด์.
- ์๋ช ์์ฑ: ํค๋์ ํ์ด๋ก๋๋ฅผ ๋น๋ฐ ํค๋ก ์๋ช ํด์.
- ํ ํฐ ์กฐํฉ: ํค๋, ํ์ด๋ก๋, ์๋ช ์ ์ (.)์ผ๋ก ๊ตฌ๋ถํด ํ๋์ ๋ฌธ์์ด๋ก ๋ง๋ค์ด์.
์ด๋ ๊ฒ ๋ง๋ค์ด์ง JWT๋ ๋ง์น ํน๋ณํ ์ํธ๋ฌธ ๊ฐ์ ๋ณด์ด์ง๋ง, ์ฌ์ค ๋๊ตฌ๋ ์ฝ์ ์ ์์ด์. ๋ค๋ง, ์๋ช ๋ถ๋ถ์ ๋น๋ฐ ํค ์์ด๋ ๋ง๋ค ์ ์๋ต๋๋ค.
๐ญ ์ฌ๋ฏธ์๋ ๋น์ : JWT ์์ฑ ๊ณผ์ ์ ๋ง์น ํน๋ณํ ํธ์ง๋ฅผ ์ฐ๋ ๊ฒ๊ณผ ๊ฐ์์. ํธ์ง์ง(ํค๋)๋ฅผ ๊ณ ๋ฅด๊ณ , ๋ด์ฉ(ํ์ด๋ก๋)์ ์ด ๋ค์, ๋ด์ธ(์๋ช )์ ํ๋ ๊ฑฐ์ฃ . ์ด๋ ๊ฒ ๋ง๋ค์ด์ง ํธ์ง๋ ๋๊ตฌ๋ ๋ณผ ์ ์์ง๋ง, ๋ด์ธ์ ๋ฏ์ง ์๊ณ ๋ ๋ด์ฉ์ ๋ฐ๊ฟ ์ ์์ด์!
2. ํ ํฐ ๊ฒ์ฆ ๋จ๊ณ ๐ต๏ธโโ๏ธ
ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ์์ฒญ์ ๋ณด๋ผ ๋ JWT๋ฅผ ํจ๊ป ๋ณด๋ด๋ฉด, ์๋ฒ๋ ์ด๋ฅผ ๊ฒ์ฆํด์. ์ด ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ์์:
- ํ ํฐ ๋ถ๋ฆฌ: ๋ฐ์ JWT๋ฅผ ํค๋, ํ์ด๋ก๋, ์๋ช ์ผ๋ก ๋ถ๋ฆฌํด์.
- ์๋ช ๊ฒ์ฆ: ํค๋์ ํ์ด๋ก๋๋ฅผ ์ฌ์ฉํด ์๋ก์ด ์๋ช ์ ๋ง๋ค๊ณ , ๋ฐ์ ์๋ช ๊ณผ ๋น๊ตํด์.
- ํ์ด๋ก๋ ํ์ธ: ์๋ช ์ด ์ผ์นํ๋ฉด ํ์ด๋ก๋์ ์ ๋ณด๋ฅผ ์ ๋ขฐํ๊ณ ์ฌ์ฉํด์.
์ด ๊ณผ์ ์ ํตํด ์๋ฒ๋ ํ ํฐ์ด ๋ณ์กฐ๋์ง ์์์์ ํ์ธํ๊ณ , ์ฌ์ฉ์์ ์ ์๊ณผ ๊ถํ์ ์์ ํ๊ฒ ํ์ธํ ์ ์์ด์.
์ด ๊ทธ๋ฆผ์ ๋ณด๋ฉด JWT์ ์ ์ฒด์ ์ธ ํ๋ฆ์ ์ดํดํ๊ธฐ ์ฝ์ฃ ? ํด๋ผ์ด์ธํธ๊ฐ ๋ก๊ทธ์ธํ๋ฉด ์๋ฒ๊ฐ JWT๋ฅผ ์์ฑํด ๋ฐํํ๊ณ , ์ดํ ํด๋ผ์ด์ธํธ๋ ์ด JWT๋ฅผ ์ฌ์ฉํด ์๋ฒ์ ์์ฒญ์ ๋ณด๋ด์. ์๋ฒ๋ JWT๋ฅผ ๊ฒ์ฆํ๊ณ ์ ์ ํ ์๋ต์ ๋ณด๋ด์ฃ .
JWT์ ๊ฐ์ฅ ํฐ ํน์ง์ ์ํ๋ฅผ ์ ์ฅํ์ง ์๋๋ค๋ ์ ์ด์์. ์ด๊ฒ ๋ฌด์จ ๋ง์ด๋๊ณ ์? ์ ํต์ ์ธ ์ธ์ ๊ธฐ๋ฐ ์ธ์ฆ์์๋ ์๋ฒ๊ฐ ์ฌ์ฉ์์ ๋ก๊ทธ์ธ ์ํ๋ฅผ ๊ณ์ ๊ธฐ์ตํ๊ณ ์์ด์ผ ํ์ด์. ํ์ง๋ง JWT๋ฅผ ์ฌ์ฉํ๋ฉด, ์๋ฒ๋ ์ฌ์ฉ์์ ์ํ๋ฅผ ๊ธฐ์ตํ ํ์๊ฐ ์์ด์. ๋์ ํด๋ผ์ด์ธํธ๊ฐ JWT๋ฅผ ๊ฐ์ง๊ณ ์๋ค๊ฐ, ํ์ํ ๋๋ง๋ค ์๋ฒ์ ๋ณด๋ด๋ ๋ฐฉ์์ด์ฃ .
์ด๋ฐ ํน์ฑ ๋๋ฌธ์ JWT๋ ํนํ ๋ค์๊ณผ ๊ฐ์ ์ํฉ์์ ์ ์ฉํด์:
- ๋ถ์ฐ ์์คํ : ์ฌ๋ฌ ์๋ฒ๋ ์๋น์ค ๊ฐ์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฝ๊ฒ ๊ณต์ ํ ์ ์์ด์.
- ๋ชจ๋ฐ์ผ ์ ํ๋ฆฌ์ผ์ด์ : ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ์ ๋ชจ๋ฐ์ผ ํ๊ฒฝ์ ํนํ ์ ํฉํด์.
- ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ: ๊ฐ ์๋น์ค๊ฐ ๋ ๋ฆฝ์ ์ผ๋ก ์ฌ์ฉ์ ์ธ์ฆ์ ์ฒ๋ฆฌํ ์ ์์ด์.
์๋ฅผ ๋ค์ด, ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์์ JWT๋ฅผ ์ฌ์ฉํ๋ฉด ์ฌ์ฉ์๊ฐ ํ ๋ฒ ๋ก๊ทธ์ธํ ํ ์ฌ๋ฌ ์๋น์ค(์: ํ๋กํ ๊ด๋ฆฌ, ๋ฉ์์ง, ๊ฒฐ์ ๋ฑ)๋ฅผ ์ํํ๊ฒ ์ด์ฉํ ์ ์์ด์. ๊ฐ ์๋น์ค๋ JWT๋ฅผ ํตํด ์ฌ์ฉ์์ ์ ์๊ณผ ๊ถํ์ ์ฝ๊ฒ ํ์ธํ ์ ์๊ธฐ ๋๋ฌธ์ด์ฃ .
๐ก ํฅ๋ฏธ๋ก์ด ์ฌ์ค: JWT์ ์ด๋ฐ ํน์ฑ์ ๋ง์น ๋์งํธ ์ฌ๊ถ๊ณผ ๊ฐ์์! ์ค์ ์ฌ๊ถ์ ์ฌ์ฉํ ๋, ๋งค๋ฒ ๋น์ ์ ์ ์์ ์ฒ์๋ถํฐ ํ์ธํ์ง ์์ฃ . ๋์ ์ฌ๊ถ ์์ฒด๊ฐ ๋น์ ์ ์ ์์ ์ฆ๋ช ํด์. JWT๋ ๋ง์ฐฌ๊ฐ์ง์์. ํ ๋ฒ ๋ฐ๊ธ๋ฐ์ JWT๋ ๊ทธ ์์ฒด๋ก ์ฌ์ฉ์์ ์ ์์ ์ฆ๋ช ํ๋ ์ญํ ์ ํ๋ ๊ฑฐ์ฃ !
ํ์ง๋ง JWT๋ ์๋ฒฝํ ์๋ฃจ์ ์ ์๋์์. ๋ช ๊ฐ์ง ์ฃผ์ํด์ผ ํ ์ ์ด ์์ฃ :
- ํ ํฐ ํฌ๊ธฐ: JWT์ ๋๋ฌด ๋ง์ ์ ๋ณด๋ฅผ ๋ด์ผ๋ฉด ํ ํฐ์ ํฌ๊ธฐ๊ฐ ์ปค์ง ์ ์์ด์.
- ๋ณด์: ๋น๋ฐ ํค๊ฐ ๋ ธ์ถ๋๋ฉด ํ ํฐ์ ์์กฐํ ์ ์์ด์. ํค ๊ด๋ฆฌ๊ฐ ๋งค์ฐ ์ค์ํด์.
- ํ ํฐ ํ๊ธฐ: ์ผ๋จ ๋ฐ๊ธ๋ ํ ํฐ์ ๋ง๋ฃ๋๊ธฐ ์ ๊น์ง ๊ณ์ ์ ํจํด์. ์ค๊ฐ์ ํ ํฐ์ ๋ฌดํจํํ๊ธฐ ์ด๋ ค์ธ ์ ์์ฃ .
์ด๋ฐ ์ ๋ค์ ๊ณ ๋ คํ๋ฉด์ JWT๋ฅผ ์ฌ์ฉํ๋ฉด, ์์ ํ๊ณ ํจ์จ์ ์ธ ์ธ์ฆ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ด์. ํนํ ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ๋ค์ํ ์๋น์ค๋ฅผ ์ ๊ณตํ๋ ํ๋ซํผ์์๋ JWT์ ์ฅ์ ์ ์ญ๋ถ ํ์ฉํ ์ ์๋ต๋๋ค!
์, ์ด์ JWT์ ์๋ ์๋ฆฌ์ ๋ํด ๊ฝค ์์ธํ ์์๋ดค์ด์. ์ด๋ ์ ๊ฐ์? JWT๊ฐ ๋ง๋ฒ ๊ฐ์ ์กด์ฌ๊ฐ ์๋๋ผ ๋ ผ๋ฆฌ์ ์ด๊ณ ์ฒด๊ณ์ ์ธ ์ธ์ฆ ๋ฐฉ์์ด๋ผ๋ ๊ฑธ ์ดํดํ์ จ๋์? ๋ค์ ์น์ ์์๋ ์ค์ ๋ก JWT๋ฅผ ์ด๋ป๊ฒ ๊ตฌํํ๋์ง ๋ ์์ธํ ์์๋ณผ ๊ฑฐ์์. ์ค๋น๋์ จ๋์? Let's code! ๐ฉโ๐ป๐จโ๐ป
๐ ๏ธ JWT ๊ตฌํํ๊ธฐ - ์ฝ๋๋ก ๋ณด๋ JWT์ ์ธ๊ณ
์, ์ด์ ์ ๋ง ์ฌ๋ฏธ์๋ ๋ถ๋ถ์ด ์์ด์! ์ฐ๋ฆฌ๊ฐ ์ง๊ธ๊น์ง ๋ฐฐ์ด JWT๋ฅผ ์ค์ ๋ก ์ด๋ป๊ฒ ๊ตฌํํ๋์ง ์์๋ณผ ๊ฑฐ์์. ๋ง์น ๋ ๊ณ ๋ธ๋ก์ ์กฐ๋ฆฝํ๋ฏ์ด, ํ๋์ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ๋ง๋ค์ด ๋ณผ๊ฒ์. ์ค๋น๋์ จ๋์? ๐
1. JWT ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ํํ๊ธฐ
JWT๋ฅผ ๊ตฌํํ๊ธฐ ์ํด์๋ ๋จผ์ ์ ์ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ ํํด์ผ ํด์. ์ฌ๋ฌ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์์ JWT๋ฅผ ์ง์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ต๋๋ค. ์ฐ๋ฆฌ๋ Node.js๋ฅผ ์ฌ์ฉํด์ ์์ ๋ฅผ ๋ง๋ค์ด๋ณผ ๊ฑฐ์์.
Node.js์์๋ 'jsonwebtoken' ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ฐ์ฅ ๋๋ฆฌ ์ฌ์ฉ๋ผ์. ๋ค์ ๋ช ๋ น์ด๋ก ์ค์นํ ์ ์์ด์:
npm install jsonwebtoken
2. JWT ์์ฑํ๊ธฐ
์ด์ JWT๋ฅผ ์์ฑํ๋ ์ฝ๋๋ฅผ ์์ฑํด๋ณผ๊ฒ์. ์๋ ์ฝ๋๋ฅผ ๋ฐ๋ผํด๋ณด์ธ์:
const jwt = require('jsonwebtoken');
const secretKey = 'your-secret-key'; // ์ค์ ์ฌ์ฉ ์ ์์ ํ๊ฒ ๊ด๋ฆฌํด์ผ ํด์!
function generateToken(userId) {
const payload = {
userId: userId,
// ํ์ํ ๋ค๋ฅธ ์ ๋ณด๋ค์ ์ฌ๊ธฐ์ ์ถ๊ฐํ ์ ์์ด์
};
const options = {
expiresIn: '1h' // ํ ํฐ์ ์ ํจ ๊ธฐ๊ฐ์ 1์๊ฐ์ผ๋ก ์ค์
};
return jwt.sign(payload, secretKey, options);
}
// ์ฌ์ฉ ์์
const token = generateToken(123);
console.log('Generated Token:', token);
์ด ์ฝ๋์์ ์ฐ๋ฆฌ๋ ์ฌ์ฉ์ ID๋ฅผ ๋ฐ์ JWT๋ฅผ ์์ฑํ๋ ํจ์๋ฅผ ๋ง๋ค์์ด์. ํ์ด๋ก๋์๋ ์ฌ์ฉ์ ID๊ฐ ํฌํจ๋์ด ์๊ณ , ํ ํฐ์ ์ ํจ ๊ธฐ๊ฐ์ 1์๊ฐ์ผ๋ก ์ค์ ํ์ด์. ์ค์ ์ฌ์ฉ ์์๋ ๋น๋ฐ ํค๋ฅผ ์์ ํ๊ฒ ๊ด๋ฆฌํด์ผ ํ๋ค๋ ์ ์ ๊ผญ ๊ธฐ์ตํ์ธ์!
๐ ๋ณด์ ํ: ๋น๋ฐ ํค๋ ์ ๋๋ก ์ฝ๋์ ์ง์ ์์ฑํ๋ฉด ์ ๋ผ์. ๋์ ํ๊ฒฝ ๋ณ์๋ ์์ ํ ์ค์ ํ์ผ์ ์ฌ์ฉํ์ธ์. ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ ๋ซํผ์์๋ ์ด๋ฐ ์ค์ํ ์ ๋ณด๋ฅผ ๋์ฑ ์ฒ ์ ํ ๊ด๋ฆฌํด์ผ ํด์!
3. JWT ๊ฒ์ฆํ๊ธฐ
ํ ํฐ์ ์์ฑํ์ผ๋, ์ด์ ์ด๋ฅผ ๊ฒ์ฆํ๋ ๋ฐฉ๋ฒ์ ์์๋ณผ๊น์? ๋ค์ ์ฝ๋๋ฅผ ์ดํด๋ณด์ธ์:
function verifyToken(token) {
try {
const decoded = jwt.verify(token, secretKey);
return decoded;
} catch(err) {
console.error('Token verification failed:', err.message);
return null;
}
}
// ์ฌ์ฉ ์์
const decodedToken = verifyToken(token);
if (decodedToken) {
console.log('Decoded Token:', decodedToken);
console.log('User ID:', decodedToken.userId);
} else {
console.log('Invalid token');
}
์ด ํจ์๋ ํ ํฐ์ ๋ฐ์์ ๊ฒ์ฆํ๊ณ , ์ ํจํ ๊ฒฝ์ฐ ๋์ฝ๋ฉ๋ ์ ๋ณด๋ฅผ ๋ฐํํด์. ๋ง์ฝ ํ ํฐ์ด ์ ํจํ์ง ์๊ฑฐ๋ ๋ง๋ฃ๋์๋ค๋ฉด, ์๋ฌ๋ฅผ ์บ์นํ๊ณ null์ ๋ฐํํ์ฃ .
4. Express.js์์ JWT ์ฌ์ฉํ๊ธฐ
์ค์ ์น ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ์ด๋ป๊ฒ JWT๋ฅผ ์ฌ์ฉํ ๊น์? Express.js๋ฅผ ์ฌ์ฉํ ๊ฐ๋จํ ์์ ๋ฅผ ํตํด ์์๋ด์:
const express = require('express');
const app = express();
app.use(express.json());
// ๋ก๊ทธ์ธ ๋ผ์ฐํธ
app.post('/login', (req, res) => {
// ์ฌ๊ธฐ์๋ ๊ฐ๋จํ ์ฒ๋ฆฌํ์ง๋ง, ์ค์ ๋ก๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ฌ์ฉ์ ํ์ธ์ ํด์ผ ํด์
const { username, password } = req.body;
if (username === 'user' && password === 'password') {
const token = generateToken(username);
res.json({ token });
} else {
res.status(401).json({ message: '์ธ์ฆ ์คํจ' });
}
});
// ๋ณดํธ๋ ๋ผ์ฐํธ
app.get('/protected', (req, res) => {
const token = req.headers['authorization'];
if (!token) {
return res.status(401).json({ message: 'ํ ํฐ์ด ์์ต๋๋ค' });
}
const decoded = verifyToken(token);
if (!decoded) {
return res.status(401).json({ message: '์ ํจํ์ง ์์ ํ ํฐ์
๋๋ค' });
}
res.json({ message: '๋ณดํธ๋ ๋ฆฌ์์ค์ ์ ๊ทผ ์ฑ๊ณต!', user: decoded.userId });
});
app.listen(3000, () => console.log('Server running on port 3000'));
์ด ์์ ์์๋ ๋ ๊ฐ์ ๋ผ์ฐํธ๋ฅผ ๋ง๋ค์์ด์:
- /login: ์ฌ์ฉ์ ์ธ์ฆ์ ์ํํ๊ณ JWT๋ฅผ ๋ฐ๊ธํด์.
- /protected: JWT๋ฅผ ์๊ตฌํ๋ ๋ณดํธ๋ ๋ฆฌ์์ค์์. ์ ํจํ ํ ํฐ์ด ์์ด์ผ๋ง ์ ๊ทผํ ์ ์์ฃ .
๐ก ์ค์ ๊ตฌํ ํ: ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํด ํ ํฐ ๊ฒ์ฆ์ ๋ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ด์. ์๋ฅผ ๋ค์ด, ๋ชจ๋ ๋ณดํธ๋ ๋ผ์ฐํธ์ ๋ํด ํ ํฐ์ ๊ฒ์ฆํ๋ ๋ฏธ๋ค์จ์ด๋ฅผ ๋ง๋ค ์ ์์ฃ .
5. JWT ์ฌ์ฉ ์ ์ฃผ์์ฌํญ
JWT๋ฅผ ์ฌ์ฉํ ๋ ๋ช ๊ฐ์ง ์ฃผ์ํด์ผ ํ ์ ์ด ์์ด์:
- ํ ํฐ ์ ์ฅ: ํด๋ผ์ด์ธํธ ์ธก์์ ํ ํฐ์ ์์ ํ๊ฒ ์ ์ฅํด์ผ ํด์. ์ผ๋ฐ์ ์ผ๋ก HttpOnly ์ฟ ํค๋ ๋ก์ปฌ ์คํ ๋ฆฌ์ง๋ฅผ ์ฌ์ฉํ์ฃ .
- ํ ํฐ ๊ฐฑ์ : ์ฅ๊ธฐ๊ฐ ์ ํจํ ํ ํฐ์ ๋ณด์ ์ํ์ด ์์ด์. ์ฃผ๊ธฐ์ ์ผ๋ก ํ ํฐ์ ๊ฐฑ์ ํ๋ ์ ๋ต์ ์ธ์์ผ ํด์.
- HTTPS ์ฌ์ฉ: JWT๋ฅผ ์ ์กํ ๋๋ ๋ฐ๋์ HTTPS๋ฅผ ์ฌ์ฉํด์ผ ํด์. ์ํธํ๋์ง ์์ ์ฑ๋๋ก ์ ์กํ๋ฉด ํ ํฐ์ด ํ์ทจ๋ ์ ์์ด์.
- ๋ฏผ๊ฐํ ์ ๋ณด ์ ์ธ: JWT ํ์ด๋ก๋์๋ ์ํธ๋ ์ ์ฉ์นด๋ ์ ๋ณด ๊ฐ์ ๋ฏผ๊ฐํ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ์ง ๋ง์์ผ ํด์.
์ด๋ ๊ฒ ํด์ ์ฐ๋ฆฌ๋ JWT๋ฅผ ์ค์ ๋ก ์ด๋ป๊ฒ ๊ตฌํํ๋์ง ์์๋ดค์ด์. ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์์๋ ์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ์ ์ธ์ฆ์ ์ฒ๋ฆฌํ๊ณ , ์ฌ๋ฌ ์๋น์ค ๊ฐ์ ์์ ํ๊ฒ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ณต์ ํ ์ ์์ด์.
JWT๋ ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ์ง๋ง, ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ด ์ค์ํด์. ๋ณด์์ ์ ๊ฒฝ ์ฐ๋ฉด์ ๊ตฌํํ๋ค๋ฉด, ์ฌ์ฉ์๋ค์๊ฒ ์์ ํ๊ณ ํธ๋ฆฌํ ์๋น์ค๋ฅผ ์ ๊ณตํ ์ ์์ ๊ฑฐ์์!
์ด ๋ค์ด์ด๊ทธ๋จ์ JWT ๊ตฌํ์ ์ ์ฒด ๊ณผ์ ์ ๋ณด์ฌ์ค์. ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ ํ๋ถํฐ ์์ํด์, JWT ์์ฑ๊ณผ ๊ฒ์ฆ, Express.js์์ ํตํฉ, ๊ทธ๋ฆฌ๊ณ ๋ณด์ ๊ณ ๋ ค์ฌํญ๊น์ง ๋ชจ๋ ๋จ๊ณ๊ฐ ์์ ํ JWT ๊ตฌํ์ผ๋ก ์ด์ด์ง๋ ๊ฒ์ ๋ณผ ์ ์์ฃ .
์, ์ด์ ์ฌ๋ฌ๋ถ์ JWT์ ๊ธฐ๋ณธ๋ถํฐ ์ค์ ๊ตฌํ๊น์ง ๋ชจ๋ ๊ฒ์ ์๊ฒ ๋์์ด์! ์ด ์ง์์ ๋ฐํ์ผ๋ก ์์ ํ๊ณ ํจ์จ์ ์ธ ์ธ์ฆ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ ๊ฑฐ์์. ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์์๋ ์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ์ ์ธ์ฆ์ ์ฒ๋ฆฌํ๊ณ ์๋ค๋ ๊ฑธ ๊ธฐ์ตํ์ธ์. ์ฌ๋ฌ๋ถ๋ ์ด์ JWT์ ์ ๋ฌธ๊ฐ๊ฐ ๋ ๊ฒ ๊ฐ์๋ฐ์? ๐
๋ค์ ์น์ ์์๋ JWT์ ์ฅ๋จ์ ์ ๋ ์์ธํ ์ดํด๋ณด๊ณ , ์ธ์ JWT๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์ง์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ๊ฒ์. ์ค๋น๋์ จ๋์? ๊ณ์ํด์ JWT์ ์ธ๊ณ๋ฅผ ํํํด๋ด ์๋ค! ๐
๐ค JWT์ ์ฅ๋จ์ ๊ณผ ์ฌ์ฉ ์๋๋ฆฌ์ค
์, ์ด์ ์ฐ๋ฆฌ๋ JWT๊ฐ ๋ฌด์์ธ์ง, ์ด๋ป๊ฒ ์๋ํ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ป๊ฒ ๊ตฌํํ๋์ง ์๊ฒ ๋์์ด์. ํ์ง๋ง ๋ชจ๋ ๊ธฐ์ ์ด ๊ทธ๋ ๋ฏ, JWT๋ ์ฅ์ ๊ณผ ๋จ์ ์ด ์๋ต๋๋ค. ์ด๋ฒ ์น์ ์์๋ JWT์ ์ฅ๋จ์ ์ ์ดํด๋ณด๊ณ , ์ด๋ค ์ํฉ์์ JWT๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์์ง ์์๋ณผ๊ฒ์.
JWT์ ์ฅ์ ๐
- ์ํ ๋น์ ์ฅ(Stateless): ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ์ ์ํ๋ฅผ ์ ์ฅํ ํ์๊ฐ ์์ด์. ์ด๋ ์๋ฒ์ ํ์ฅ์ฑ์ ๋์ฌ์ค๋๋ค.
- ํ์ฅ์ฑ: ํ ํฐ ๊ธฐ๋ฐ ์์คํ ์ ์ฌ๋ฌ ์๋ฒ์ ์๋น์ค์์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ด์.
- ๋ชจ๋ฐ์ผ ์นํ์ : ๋ชจ๋ฐ์ผ ํ๊ฒฝ์์ ์ฟ ํค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ํ ํฐ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ฝ๊ณ ์์ ํด์.
- ๊ต์ฐจ ๋๋ฉ์ธ / CORS: ํ ํฐ์ ์ฌ๋ฌ ๋๋ฉ์ธ์์ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์์ด์.
- ์ฑ๋ฅ: ํ ๋ฒ ์์ฑ๋ ํ ํฐ์ ๊ฒ์ฆ๋ง ํ๋ฉด ๋๋ฏ๋ก, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ๊ฐ ํ์ ์์ด ์ฑ๋ฅ์ด ์ข์์.
JWT์ ๋จ์ ๐
- ํ ํฐ ํฌ๊ธฐ: JWT๋ ์ธ์ ID์ ๋นํด ํฌ๊ธฐ๊ฐ ์ปค์ ๋คํธ์ํฌ ๋ถํ๊ฐ ์ฆ๊ฐํ ์ ์์ด์.
- ๋ณด์: ํ ํฐ์ด ํ์ทจ๋๋ฉด ๋ง๋ฃ๋ ๋๊น์ง ๊ณ์ ์ฌ์ฉ๋ ์ ์์ด์. ์ ์ ํ ๋ง๋ฃ ์๊ฐ ์ค์ ์ด ์ค์ํด์.
- ํ ํฐ ์ ์ฅ: ํด๋ผ์ด์ธํธ ์ธก์์ ํ ํฐ์ ์์ ํ๊ฒ ์ ์ฅํ๋ ๊ฒ์ด ์ค์ํด์.
- ๋ฌดํจํ์ ์ด๋ ค์: ํ ๋ฒ ๋ฐ๊ธ๋ ํ ํฐ์ ์๋ฒ ์ธก์์ ์ฆ์ ๋ฌดํจํํ๊ธฐ ์ด๋ ค์์.
- Payload ์ ํ: ํ ํฐ์ ๋๋ฌด ๋ง์ ์ ๋ณด๋ฅผ ๋ด์ผ๋ฉด ํฌ๊ธฐ๊ฐ ์ปค์ ธ ์ฑ๋ฅ์ ์ํฅ์ ์ค ์ ์์ด์.
๐ก ์ฌ๋ฅ๋ท ํ์ฉ ํ: ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์์ JWT๋ฅผ ์ฌ์ฉํ ๋๋ ํ ํฐ์ ๋ง๋ฃ ์๊ฐ์ ์ ์ ํ ์ค์ ํ๊ณ , ์ค์ํ ์์ (์: ๊ฒฐ์ , ํ๋กํ ๋ณ๊ฒฝ)์๋ ์ถ๊ฐ์ ์ธ ์ธ์ฆ ๋จ๊ณ๋ฅผ ๋๋ ๊ฒ์ด ์ข์์. ์ด๋ ๊ฒ ํ๋ฉด ๋ณด์์ ๊ฐํํ๋ฉด์๋ ์ฌ์ฉ์ ๊ฒฝํ์ ํด์น์ง ์์ ์ ์์ด์.
JWT ์ฌ์ฉ์ด ์ ํฉํ ์๋๋ฆฌ์ค ๐ญ
- ๋จ์ผ ํ์ด์ง ์ ํ๋ฆฌ์ผ์ด์ (SPA): React, Vue, Angular ๋ฑ์ผ๋ก ๋ง๋ SPA์์ JWT๋ ๋งค์ฐ ํจ๊ณผ์ ์ด์์.
- ๋ชจ๋ฐ์ผ ์ ํ๋ฆฌ์ผ์ด์ : ๋ค์ดํฐ๋ธ ๋ชจ๋ฐ์ผ ์ฑ์์ ์๋ฒ์ ํต์ ํ ๋ JWT๋ฅผ ์ฌ์ฉํ๋ฉด ํธ๋ฆฌํด์.
- ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ: ์ฌ๋ฌ ์๋น์ค ๊ฐ์ ์ฌ์ฉ์ ์ธ์ฆ ์ ๋ณด๋ฅผ ๊ณต์ ํ ๋ JWT๊ฐ ์ ์ฉํด์.
- API ์ธ์ฆ: ์๋ํํฐ ์ ํ๋ฆฌ์ผ์ด์ ์ API ์ ๊ทผ ๊ถํ์ ๋ถ์ฌํ ๋ JWT๋ฅผ ์ฌ์ฉํ ์ ์์ด์.
- ์๋ฒ๋ฆฌ์ค ์ํคํ ์ฒ: AWS Lambda ๊ฐ์ ์๋ฒ๋ฆฌ์ค ํ๊ฒฝ์์ JWT๋ ์ํ ๋น์ ์ฅ ํน์ฑ ๋๋ฌธ์ ์ ํฉํด์.
JWT ์ฌ์ฉ์ด ๋ถ์ ํฉํ ์๋๋ฆฌ์ค ๐ซ
- ๋ณต์กํ ๊ถํ ๊ด๋ฆฌ๊ฐ ํ์ํ ๊ฒฝ์ฐ: ์ฌ์ฉ์์ ๊ถํ์ด ์์ฃผ ๋ณ๊ฒฝ๋๋ ์์คํ ์์๋ JWT ์ฌ์ฉ์ด ์ด๋ ค์ธ ์ ์์ด์.
- ์ค์๊ฐ ํ ํฐ ๋ฌดํจํ๊ฐ ํ์ํ ๊ฒฝ์ฐ: ์ฆ์ ์ฌ์ฉ์์ ์ ๊ทผ์ ์ฐจ๋จํด์ผ ํ๋ ์ํฉ์์๋ JWT๊ฐ ์ ํฉํ์ง ์์ ์ ์์ด์.
- ๋์ฉ๋ ๋ฐ์ดํฐ ์ ์ฅ์ด ํ์ํ ๊ฒฝ์ฐ: JWT์ ๋๋ฌด ๋ง์ ๋ฐ์ดํฐ๋ฅผ ๋ด์ผ๋ฉด ์ฑ๋ฅ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ด์.
์ด ๋ค์ด์ด๊ทธ๋จ์ JWT๊ฐ ์ ํฉํ ์๋๋ฆฌ์ค์ ๋ถ์ ํฉํ ์๋๋ฆฌ์ค๋ฅผ ํ๋์ ๋ณด์ฌ์ค์. ์ผ์ชฝ์ ํ๋์ ์์ญ์ JWT๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ฌ์ฉํ ์ ์๋ ์ํฉ๋ค์, ์ค๋ฅธ์ชฝ์ ๋นจ๊ฐ์ ์์ญ์ JWT ์ฌ์ฉ์ด ์ด๋ ค์ธ ์ ์๋ ์ํฉ๋ค์ ๋ํ๋ด๊ณ ์์ด์.
์, ์ด์ ์ฐ๋ฆฌ๋ JWT์ ์ฅ๋จ์ ๊ณผ ์ ์ ํ ์ฌ์ฉ ์๋๋ฆฌ์ค์ ๋ํด ์์๋ดค์ด์. JWT๋ ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ์ง๋ง, ๋ชจ๋ ์ํฉ์ ์ ํฉํ ๋ง๋ฅ ํด๊ฒฐ์ฑ ์ ์๋์์. ํ๋ก์ ํธ์ ํน์ฑ๊ณผ ์๊ตฌ์ฌํญ์ ์ ๊ณ ๋ คํด์ JWT ์ฌ์ฉ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํด์ผ ํด์.
์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์์๋ JWT์ ์ฅ์ ์ ์ ํ์ฉํ๋ฉด์๋ ๋จ์ ์ ๋ณด์ํ๋ ์ ๋ต์ด ํ์ํด์. ์๋ฅผ ๋ค์ด, ํ ํฐ์ ๋ง๋ฃ ์๊ฐ์ ์งง๊ฒ ์ค์ ํ๊ณ ์ฃผ๊ธฐ์ ์ผ๋ก ๊ฐฑ์ ํ๋ ๋ฐฉ์์ ์ฌ์ฉํ๊ฑฐ๋, ์ค์ํ ์์ ์๋ ์ถ๊ฐ์ ์ธ ์ธ์ฆ ๋จ๊ณ๋ฅผ ๋๋ ๋ฑ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ ์ ์์ด์.
์ฌ๋ฌ๋ถ๋ ์ด์ JWT์ ์ฅ๋จ์ ์ ์ ์ดํดํ์ จ์ฃ ? ์ด ์ง์์ ๋ฐํ์ผ๋ก ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ์ ๊ฐ์ฅ ์ ํฉํ ์ธ์ฆ ๋ฐฉ์์ ์ ํํ ์ ์์ ๊ฑฐ์์. JWT๊ฐ ํ์ํ ์ํฉ์ธ์ง, ์๋๋ฉด ๋ค๋ฅธ ๋ฐฉ์์ด ๋ ์ข์์ง ํ๋ช ํ๊ฒ ํ๋จํ ์ ์๊ฒ ๋์๋ต๋๋ค! ๐ง ๐ก
๋ค์ ์น์ ์์๋ JWT๋ฅผ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ ๋ ์ฃผ์ํด์ผ ํ ๋ณด์ ์ฌํญ๋ค์ ๋ํด ๋ ์์ธํ ์์๋ณผ๊ฒ์. JWT๋ฅผ ์์ ํ๊ฒ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ, ๊ผญ ์์์ผ๊ฒ ์ฃ ? ํจ๊ป ์์๋ด์! ๐
๐ก๏ธ JWT ๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก - ์์ ํ ์ธ์ฆ์ ์ด์
์๋ ํ์ธ์, ๋ณด์ ์ ๋ฌธ๊ฐ ์ฌ๋ฌ๋ถ! (๋ค, ์ฌ๋ฌ๋ถ๋ ์ด์ JWT ๋ณด์ ์ ๋ฌธ๊ฐ์์! ๐) ์ด๋ฒ ์น์ ์์๋ JWT๋ฅผ ์ฌ์ฉํ ๋ ๊ผญ ์์์ผ ํ ๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก์ ๋ํด ์์๋ณผ ๊ฑฐ์์. JWT๋ ๊ฐ๋ ฅํ ๋๊ตฌ์ง๋ง, ์๋ชป ์ฌ์ฉํ๋ฉด ๋ณด์ ์ทจ์ฝ์ ์ด ๋ ์ ์์ด์. ๊ทธ๋์ ์ฐ๋ฆฌ๋ JWT๋ฅผ ์์ ํ๊ฒ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๊ผญ ์์์ผ ํด์!
1. ์์ ํ ํค ๊ด๋ฆฌ ๐
JWT์ ๋ณด์์ ๋น๋ฐ ํค์ ๋ฌ๋ ค์์ด์. ๋น๋ฐ ํค ๊ด๋ฆฌ์ ์ ๊ฒฝ ์ฐ์ง ์์ผ๋ฉด ๋ชจ๋ ๋ ธ๋ ฅ์ด ๋ฌผ๊ฑฐํ์ด ๋ ์ ์์ฃ .
- ๊ฐ๋ ฅํ ํค ์ฌ์ฉ: ์ต์ 256๋นํธ ๊ธธ์ด์ ๋๋คํ๊ณ ๋ณต์กํ ํค๋ฅผ ์ฌ์ฉํ์ธ์.
- ํค ๋กํ ์ด์ : ์ ๊ธฐ์ ์ผ๋ก ํค๋ฅผ ๋ณ๊ฒฝํ์ธ์. ์ด๋ ๊ฒ ํ๋ฉด ํค๊ฐ ๋ ธ์ถ๋๋๋ผ๋ ํผํด๋ฅผ ์ต์ํํ ์ ์์ด์.
- ํ๊ฒฝ ๋ณ์ ์ฌ์ฉ: ํค๋ฅผ ์ฝ๋์ ์ง์ ์์ฑํ์ง ๋ง๊ณ , ํ๊ฒฝ ๋ณ์๋ ์์ ํ ํค ๊ด๋ฆฌ ์์คํ ์ ์ฌ์ฉํ์ธ์.
โ ๏ธ ์ฃผ์: ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์์๋ ํค ๊ด๋ฆฌ๊ฐ ํนํ ์ค์ํด์. ์ฌ๋ฌ ์๋น์ค์์ ๊ฐ์ ํค๋ฅผ ์ฌ์ฉํ๋ค๋ฉด, ํ๋์ ์๋น์ค๊ฐ ๋ซ๋ฆฌ๋ฉด ๋ชจ๋ ์๋น์ค๊ฐ ์ํํด์ง ์ ์์ด์!
2. ์ ์ ํ JWT ์ค์ โ๏ธ
JWT์ ์ค์ ๋ ๋ณด์์ ํฐ ์ํฅ์ ๋ฏธ์ณ์. ๋ค์ ์ฌํญ๋ค์ ๊ผญ ๊ธฐ์ตํ์ธ์:
- ์งง์ ๋ง๋ฃ ์๊ฐ: ํ ํฐ์ ์ ํจ ๊ธฐ๊ฐ์ ์งง๊ฒ ์ค์ ํ์ธ์. ๊ธธ๋ฉด ๊ธธ์๋ก ๊ณต๊ฒฉ์๊ฐ ์ด์ฉํ ์ ์๋ ์๊ฐ์ด ๋์ด๋์.
- ํ์ ํด๋ ์ ์ฌ์ฉ: 'exp'(๋ง๋ฃ ์๊ฐ), 'iat'(๋ฐ๊ธ ์๊ฐ), 'aud'(๋์) ๋ฑ์ ํด๋ ์์ ๋ฐ๋์ ํฌํจํ์ธ์.
- ์๊ณ ๋ฆฌ์ฆ ์ง์ : 'alg: none'์ ํ์ฉํ์ง ๋ง์ธ์. ํญ์ ์์ ํ ์๊ณ ๋ฆฌ์ฆ(์: RS256)์ ๋ช ์์ ์ผ๋ก ์ง์ ํ์ธ์.
// ์ข์ ์์
const token = jwt.sign(
{
userId: user.id,
exp: Math.floor(Date.now() / 1000) + (60 * 15) // 15๋ถ ํ ๋ง๋ฃ
},
process.env.JWT_SECRET,
{ algorithm: 'RS256' }
);
3. ์์ ํ ์ ์ก ๋ฐ ์ ์ฅ ๐
JWT๋ฅผ ์์ ํ๊ฒ ์ฃผ๊ณ ๋ฐ๊ณ ์ ์ฅํ๋ ๊ฒ๋ ์ค์ํด์:
- HTTPS ์ฌ์ฉ: JWT๋ ๋ฐ๋์ HTTPS๋ฅผ ํตํด ์ ์กํด์ผ ํด์. HTTP๋ก ์ ์กํ๋ฉด ์ค๊ฐ์ ๊ฐ๋ก์ฑ ์ ์์ด์.
- HttpOnly ์ฟ ํค: ๊ฐ๋ฅํ๋ฉด JWT๋ฅผ HttpOnly ์ฟ ํค์ ์ ์ฅํ์ธ์. ์ด๋ ๊ฒ ํ๋ฉด XSS ๊ณต๊ฒฉ์ผ๋ก๋ถํฐ ๋ณดํธํ ์ ์์ด์.
- Secure ํ๋๊ทธ: ์ฟ ํค์ Secure ํ๋๊ทธ๋ฅผ ์ค์ ํด HTTPS ์ฐ๊ฒฐ์์๋ง ์ ์ก๋๋๋ก ํ์ธ์.
// Express.js์์ ์ฟ ํค ์ค์ ์์
res.cookie('token', token, {
httpOnly: true,
secure: true,
sameSite: 'strict'
});
4. ํ ํฐ ๊ฒ์ฆ ์ฒ ์ ํ ํ๊ธฐ ๐
์๋ฒ์์ ํ ํฐ์ ๋ฐ์์ ๋ ์ฒ ์ ํ ๊ฒ์ฆํด์ผ ํด์:
- ์๋ช ํ์ธ: ํ ํฐ์ ์๋ช ์ด ์ ํจํ์ง ๋ฐ๋์ ํ์ธํ์ธ์.
- ๋ง๋ฃ ์๊ฐ ํ์ธ: ํ ํฐ์ด ์์ง ์ ํจํ์ง ํ์ธํ์ธ์.
- ๋์(aud) ํ์ธ: ํ ํฐ์ด ํ์ฌ ์๋น์ค๋ฅผ ์ํ ๊ฒ์ธ์ง ํ์ธํ์ธ์.
- ๋ฐ๊ธ์(iss) ํ์ธ: ํ ํฐ์ด ์ ๋ขฐํ ์ ์๋ ๋ฐ๊ธ์๋ก๋ถํฐ ์จ ๊ฒ์ธ์ง ํ์ธํ์ธ์.
// ํ ํฐ ๊ฒ์ฆ ์์
try {
const decoded = jwt.verify(token, publicKey, {
algorithms: ['RS256'],
audience: 'https://api.jaenung.net',
issuer: 'https://jaenung.net'
});
// ํ ํฐ์ด ์ ํจํจ
} catch(err) {
// ํ ํฐ์ด ์ ํจํ์ง ์์
console.error('Token verification failed:', err.message);
}
5. ์ถ๊ฐ ๋ณด์ ๊ณ์ธต ์ถ๊ฐ ๐ง
JWT๋ง์ผ๋ก๋ ๋ถ์กฑํ ์ ์์ด์. ์ถ๊ฐ์ ์ธ ๋ณด ์ ๊ณ์ธต์ ๊ณ ๋ คํด๋ณด์ธ์:
- CSRF ํ ํฐ: CSRF(Cross-Site Request Forgery) ๊ณต๊ฒฉ์ ๋ฐฉ์งํ๊ธฐ ์ํด ๋ณ๋์ CSRF ํ ํฐ์ ์ฌ์ฉํ์ธ์.
- ๋ค๋จ๊ณ ์ธ์ฆ(MFA): ์ค์ํ ์์ ์๋ ์ถ๊ฐ์ ์ธ ์ธ์ฆ ๋จ๊ณ๋ฅผ ์๊ตฌํ์ธ์.
- IP ์ ํ: ๊ฐ๋ฅํ๋ค๋ฉด ํ ํฐ ์ฌ์ฉ์ ํน์ IP ์ฃผ์๋ก ์ ํํ์ธ์.
- ํ๋ ๋ก๊น : ๋ชจ๋ ์ธ์ฆ ๊ด๋ จ ํ๋์ ๋ก๊น ํ๊ณ ๋ชจ๋ํฐ๋งํ์ธ์.
๐ก ํ: ์ฌ๋ฅ๋ท์์๋ ์ฌ์ฉ์์ ํ๋กํ ๋ณ๊ฒฝ์ด๋ ๊ฒฐ์ ์ ๊ฐ์ ์ค์ํ ์์ ์ ์ถ๊ฐ ์ธ์ฆ์ ์๊ตฌํ๋ ๊ฒ์ด ์ข์์. ์ด๋ ๊ฒ ํ๋ฉด ํ ํฐ์ด ํ์ทจ๋๋๋ผ๋ ํผํด๋ฅผ ์ต์ํํ ์ ์์ด์!
6. ํ ํฐ ๊ฐฑ์ ์ ๋ต ๐
ํ ํฐ์ ์๋ช ์ ๊ด๋ฆฌํ๋ ๊ฒ๋ ์ค์ํด์:
- ๋ฆฌํ๋ ์ ํ ํฐ ์ฌ์ฉ: ์งง์ ์๋ช ์ ์ก์ธ์ค ํ ํฐ๊ณผ ๊ธด ์๋ช ์ ๋ฆฌํ๋ ์ ํ ํฐ์ ํจ๊ป ์ฌ์ฉํ์ธ์.
- ํ ํฐ ํ์ : ๋ฆฌํ๋ ์ ํ ํฐ์ ์ฌ์ฉํ ๋๋ง๋ค ์๋ก์ด ๋ฆฌํ๋ ์ ํ ํฐ์ ๋ฐ๊ธํ์ธ์.
- ๋ฆฌํ๋ ์ ํ ํฐ ๋ฌดํจํ: ์ฌ์ฉ์๊ฐ ๋ก๊ทธ์์ํ๋ฉด ๋ฆฌํ๋ ์ ํ ํฐ์ ์ฆ์ ๋ฌดํจํํ์ธ์.
// ๋ฆฌํ๋ ์ ํ ํฐ ์ฌ์ฉ ์์
app.post('/refresh', (req, res) => {
const { refreshToken } = req.body;
if (isValidRefreshToken(refreshToken)) {
const newAccessToken = generateAccessToken(user);
const newRefreshToken = generateRefreshToken(user);
// ๊ธฐ์กด ๋ฆฌํ๋ ์ ํ ํฐ ๋ฌดํจํ
invalidateRefreshToken(refreshToken);
res.json({ accessToken: newAccessToken, refreshToken: newRefreshToken });
} else {
res.status(401).json({ error: 'Invalid refresh token' });
}
});
7. ์๋ฌ ์ฒ๋ฆฌ์ ๋ณด์ ํค๋ ๐ฆ
๋ง์ง๋ง์ผ๋ก, ์ ์ ํ ์๋ฌ ์ฒ๋ฆฌ์ ๋ณด์ ํค๋ ์ค์ ๋ ์์ง ๋ง์ธ์:
- ์์ธํ ์๋ฌ ๋ฉ์์ง ํผํ๊ธฐ: ๊ณต๊ฒฉ์์๊ฒ ์ ์ฉํ ์ ๋ณด๋ฅผ ์ ๊ณตํ์ง ์๋๋ก ์ฃผ์ํ์ธ์.
- ๋ณด์ ํค๋ ์ค์ : X-XSS-Protection, Strict-Transport-Security, Content-Security-Policy ๋ฑ์ ๋ณด์ ํค๋๋ฅผ ์ค์ ํ์ธ์.
// Express.js์์ ๋ณด์ ํค๋ ์ค์ ์์
const helmet = require('helmet');
app.use(helmet());
์ด ๋ค์ด์ด๊ทธ๋จ์ ์ฐ๋ฆฌ๊ฐ ์ง๊ธ๊น์ง ๋ฐฐ์ด JWT ๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ํ๋์ ๋ณด์ฌ์ค์. ๊ฐ๊ฐ์ ์์๊ฐ JWT์ ์ ์ฒด์ ์ธ ๋ณด์์ ๊ตฌ์ฑํ๋ ์ค์ํ ๋ถ๋ถ์ด๋ผ๋ ๊ฑธ ๊ธฐ์ตํ์ธ์!
์, ์ด์ ์ฌ๋ฌ๋ถ์ JWT๋ฅผ ์์ ํ๊ฒ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ชจ๋ ์๊ฒ ๋์์ด์! ์ด๋ฐ ๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก๋ค์ ๋ฐ๋ฅด๋ฉด, JWT๋ฅผ ์ฌ์ฉํ๋ ์ฌ๋ฌ๋ถ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํจ์ฌ ๋ ์์ ํด์ง ๊ฑฐ์์. ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์์๋ ์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ์์ ํ๊ฒ ๋ณดํธํ๊ณ ์๋ต๋๋ค.
ํ์ง๋ง ๊ธฐ์ตํ์ธ์, ๋ณด์์ ๋์์์ด ์งํํ๋ ๋ถ์ผ์์. ์๋ก์ด ์ํ์ด ๊ณ์ํด์ ๋ฑ์ฅํ๊ธฐ ๋๋ฌธ์, ํญ์ ์ต์ ๋ณด์ ๋ํฅ์ ์ฃผ์ํ๊ณ ์ฌ๋ฌ๋ถ์ ์์คํ ์ ์ง์์ ์ผ๋ก ์ ๋ฐ์ดํธํด์ผ ํด์. ๋ณด์์ ํ ๋ฒ ๊ตฌ์ถํ๊ณ ๋๋๋ ๊ฒ ์๋๋ผ, ๊ณ์ํด์ ๊ด๋ฆฌํ๊ณ ๊ฐ์ ํด์ผ ํ๋ ๊ณผ์ ์ด์์.
์ฌ๋ฌ๋ถ์ด ์ด ์ง์์ ๋ฐํ์ผ๋ก ์์ ํ๊ณ ๋ฏฟ์ ์ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ค ์ ์๊ธฐ๋ฅผ ๋ฐ๋ผ์. JWT์ ํจ๊ป ์ฌ๋ฌ๋ถ์ ์ฐฝ์์ ์ธ ์์ด๋์ด๋ฅผ ์์ ํ๊ฒ ์คํํด๋ณด์ธ์! ๐๐
๋ค์ ์น์ ์์๋ JWT๋ฅผ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ ์ค์ ์์ ๋ฅผ ์ดํด๋ณผ ๊ฑฐ์์. ์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ด์ฉ์ ์ด๋ป๊ฒ ์ค์ ๋ก ํ์ฉํ๋์ง ํจ๊ป ์์๋ณด๊ฒ ์ต๋๋ค. ์ค๋น๋์ จ๋์? let's code! ๐ฉโ๐ป๐จโ๐ป
๐ ๏ธ JWT ์ค์ ์ ์ฉ - ์ฌ๋ฅ๋ท ์คํ์ผ๋ก ๊ตฌํํ๊ธฐ
์๋ ํ์ธ์, ์ฝ๋ฉ ๊ณ ์ ์ฌ๋ฌ๋ถ! ๐๏ธ ์ด์ ์ฐ๋ฆฌ๊ฐ ๋ฐฐ์ด ๋ชจ๋ ๊ฒ์ ์ข ํฉํด์ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํด๋ณผ ์๊ฐ์ด์์. ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์ ๋ง๋ ๋ค๊ณ ์์ํด๋ณผ๊น์? JWT๋ฅผ ์ฌ์ฉํด ์์ ํ๊ณ ํจ์จ์ ์ธ ์ธ์ฆ ์์คํ ์ ๊ตฌ์ถํด๋ด ์๋ค!
1. ํ๋ก์ ํธ ์ค์
๋จผ์ ํ์ํ ํจํค์ง๋ค์ ์ค์นํด๋ณผ๊ฒ์:
npm init -y
npm install express jsonwebtoken bcrypt dotenv
๊ทธ๋ฆฌ๊ณ .env ํ์ผ์ ๋ง๋ค์ด ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์ ํด์ฃผ์ธ์:
JWT_SECRET=your_super_secret_key
JWT_EXPIRES_IN=15m
REFRESH_TOKEN_SECRET=another_super_secret_key
REFRESH_TOKEN_EXPIRES_IN=7d
2. ์๋ฒ ์ค์
์ด์ Express ์๋ฒ๋ฅผ ์ค์ ํด๋ณผ๊ฒ์:
// server.js
require('dotenv').config();
const express = require('express');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const app = express();
app.use(express.json());
// ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋์ ์์๋ก ์ฌ์ฉํ ๋ฐฐ์ด
let users = [];
let refreshTokens = [];
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
3. ์ฌ์ฉ์ ๋ฑ๋ก ๊ตฌํ
์ฌ์ฉ์ ๋ฑ๋ก ๊ธฐ๋ฅ์ ๋ง๋ค์ด๋ณผ๊ฒ์:
app.post('/register', async (req, res) => {
try {
const { username, password } = req.body;
// ์ด๋ฏธ ์กด์ฌํ๋ ์ฌ์ฉ์์ธ์ง ํ์ธ
if (users.find(user => user.username === username)) {
return res.status(400).json({ message: '์ด๋ฏธ ์กด์ฌํ๋ ์ฌ์ฉ์์
๋๋ค.' });
}
// ๋น๋ฐ๋ฒํธ ํด์ฑ
const hashedPassword = await bcrypt.hash(password, 10);
// ์ ์ฌ์ฉ์ ์ถ๊ฐ
const newUser = { id: users.length + 1, username, password: hashedPassword };
users.push(newUser);
res.status(201).json({ message: '์ฌ์ฉ์๊ฐ ์ฑ๊ณต์ ์ผ๋ก ๋ฑ๋ก๋์์ต๋๋ค.' });
} catch (error) {
res.status(500).json({ message: '์๋ฒ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.' });
}
});
4. ๋ก๊ทธ์ธ ๋ฐ ํ ํฐ ๋ฐ๊ธ ๊ตฌํ
์ด์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ๊ณผ JWT ๋ฐ๊ธ์ ๊ตฌํํด๋ณผ๊ฒ์:
app.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
// ์ฌ์ฉ์ ์ฐพ๊ธฐ
const user = users.find(user => user.username === username);
if (!user) {
return res.status(400).json({ message: '์ฌ์ฉ์๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.' });
}
// ๋น๋ฐ๋ฒํธ ํ์ธ
const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) {
return res.status(400).json({ message: '์๋ชป๋ ๋น๋ฐ๋ฒํธ์
๋๋ค.' });
}
// JWT ํ ํฐ ์์ฑ
const accessToken = jwt.sign(
{ userId: user.id, username: user.username },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN }
);
// ๋ฆฌํ๋ ์ ํ ํฐ ์์ฑ
const refreshToken = jwt.sign(
{ userId: user.id, username: user.username },
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: process.env.REFRESH_TOKEN_EXPIRES_IN }
);
// ๋ฆฌํ๋ ์ ํ ํฐ ์ ์ฅ
refreshTokens.push(refreshToken);
res.json({ accessToken, refreshToken });
} catch (error) {
res.status(500).json({ message: '์๋ฒ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.' });
}
});
5. ํ ํฐ ๊ฒ์ฆ ๋ฏธ๋ค์จ์ด ๊ตฌํ
์ด์ ๋ณดํธ๋ ๋ผ์ฐํธ์ ์ฌ์ฉํ ํ ํฐ ๊ฒ์ฆ ๋ฏธ๋ค์จ์ด๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์:
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token == null) return res.sendStatus(401);
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
}
6. ๋ณดํธ๋ ๋ผ์ฐํธ ๊ตฌํ
์ด์ ์ธ์ฆ๋ ์ฌ์ฉ์๋ง ์ ๊ทผํ ์ ์๋ ๋ผ์ฐํธ๋ฅผ ๋ง๋ค์ด๋ณผ๊ฒ์:
app.get('/protected', authenticateToken, (req, res) => {
res.json({ message: '๋ณดํธ๋ ๋ฐ์ดํฐ์ ์ ๊ทผํ์ต๋๋ค!', user: req.user });
});
7. ํ ํฐ ๊ฐฑ์ ๊ตฌํ
๋ง์ง๋ง์ผ๋ก, ๋ฆฌํ๋ ์ ํ ํฐ์ ์ฌ์ฉํด ์๋ก์ด ์ก์ธ์ค ํ ํฐ์ ๋ฐ๊ธํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํด๋ณผ๊ฒ์:
app.post('/token', (req, res) => {
const { refreshToken } = req.body;
if (refreshToken == null) return res.sendStatus(401);
if (!refreshTokens.includes(refreshToken)) return res.sendStatus(403);
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
const accessToken = jwt.sign(
{ userId: user.userId, username: user.username },
process.env.JWT_SECRET,
{ expiresIn: process.env.JWT_EXPIRES_IN }
);
res.json({ accessToken });
});
});
๐ ์ค์ ํ: ์ค์ ํ๋ก๋์ ํ๊ฒฝ์์๋ ๋ฆฌํ๋ ์ ํ ํฐ์ ๋ฉ๋ชจ๋ฆฌ ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๊ณ , ์ฃผ๊ธฐ์ ์ผ๋ก ๋ง๋ฃ๋ ํ ํฐ์ ์ ๋ฆฌํด์ผ ํด์. ๋ํ, ์ฌ์ฉ์ ๋ก๊ทธ์์ ์ ํด๋น ๋ฆฌํ๋ ์ ํ ํฐ์ ์ญ์ ํ๋ ๋ก์ง๋ ๊ตฌํํด์ผ ํฉ๋๋ค!
์, ์ด์ ์ฐ๋ฆฌ๋ JWT๋ฅผ ์ฌ์ฉํ ๊ธฐ๋ณธ์ ์ธ ์ธ์ฆ ์์คํ ์ ๊ตฌํํ์ด์! ์ด ์์คํ ์ ์ฌ์ฉ์ ๋ฑ๋ก, ๋ก๊ทธ์ธ, ํ ํฐ ๊ธฐ๋ฐ ์ธ์ฆ, ๊ทธ๋ฆฌ๊ณ ํ ํฐ ๊ฐฑ์ ๊ธฐ๋ฅ์ ํฌํจํ๊ณ ์์ด์. ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ํ๋ซํผ์์๋ ์ด์ ์ ์ฌํ ๋ฐฉ์์ผ๋ก ์ฌ์ฉ์ ์ธ์ฆ์ ์ฒ๋ฆฌํ๊ณ ์๋ต๋๋ค.
์ด ์์ ๋ฅผ ๋ฐํ์ผ๋ก, ์ฌ๋ฌ๋ถ์ ๋ค์๊ณผ ๊ฐ์ ๊ธฐ๋ฅ๋ค์ ์ถ๊ฐ๋ก ๊ตฌํํด๋ณผ ์ ์์ด์:
- ์ฌ์ฉ์ ํ๋กํ ์์ ๊ธฐ๋ฅ
- ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ๊ธฐ๋ฅ
- ์ด๋ฉ์ผ ์ธ์ฆ ๊ธฐ๋ฅ
- ์์ ๋ก๊ทธ์ธ ํตํฉ
- ๋ค๋จ๊ณ ์ธ์ฆ(MFA) ๊ตฌํ
JWT๋ฅผ ํ์ฉํ ์ธ์ฆ ์์คํ ์ ํ์ฅ์ฑ์ด ๋ฐ์ด๋๊ณ ๋ค์ํ ๊ธฐ๋ฅ์ ์ฝ๊ฒ ์ถ๊ฐํ ์ ์์ด์. ์ฌ๋ฌ๋ถ์ ์ฐฝ์๋ ฅ์ ๋ฐํํด ๋ ๋ฉ์ง ๊ธฐ๋ฅ๋ค์ ๋ง๋ค์ด๋ณด์ธ์!
๋ง์ง๋ง์ผ๋ก, ๋ณด์์ ๋์์์ด ๋ฐ์ ํ๋ ๋ถ์ผ๋ผ๋ ๊ฑธ ์์ง ๋ง์ธ์. ํญ์ ์ต์ ๋ณด์ ๋ํฅ์ ์ฃผ์ํ๊ณ , ์ฌ๋ฌ๋ถ์ ์์คํ ์ ์ง์์ ์ผ๋ก ์ ๋ฐ์ดํธํ๊ณ ๊ฐ์ ํด ๋๊ฐ๋ ๊ฒ์ด ์ค์ํด์.
์ฌ๋ฌ๋ถ์ JWT ์ฌ์ ์ด ์ฆ๊ฒ๊ณ ์์ ํ๊ธฐ๋ฅผ ๋ฐ๋๋๋ค! ํดํผ ์ฝ๋ฉ! ๐๐จโ๐ป๐ฉโ๐ป
๐ ๊ฒฐ๋ก - JWT ๋ง์คํฐ๊ฐ ๋๋ ๊ธธ
์ถํํฉ๋๋ค! ๐ ์ฌ๋ฌ๋ถ์ ์ด์ JWT์ ์ธ๊ณ๋ฅผ ๊น์ด ์๊ฒ ํํํ์ด์. JWT๊ฐ ๋ฌด์์ธ์ง, ์ด๋ป๊ฒ ์๋ํ๋์ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ป๊ฒ ์์ ํ๊ฒ ๊ตฌํํ๋์ง ๋ฐฐ์ ์ต๋๋ค. ์ด์ ์ฌ๋ฌ๋ถ์ JWT ์ ๋ฌธ๊ฐ๋ผ๊ณ ํด๋ ๊ณผ์ธ์ด ์๋์์!
์ฐ๋ฆฌ๊ฐ ํจ๊ป ๋ฐฐ์ด ๋ด์ฉ์ ๊ฐ๋จํ ์ ๋ฆฌํด๋ณผ๊น์?
- JWT์ ๊ธฐ๋ณธ ๊ฐ๋ ๊ณผ ๊ตฌ์กฐ
- JWT์ ์๋ ์๋ฆฌ
- JWT์ ์ฅ๋จ์ ๊ณผ ์ ์ ํ ์ฌ์ฉ ์๋๋ฆฌ์ค
- JWT ๋ณด์ ๋ชจ๋ฒ ์ฌ๋ก
- ์ค์ ํ๋ก์ ํธ์ JWT ์ ์ฉํ๊ธฐ
์ด ์ง์์ ๋ฐํ์ผ๋ก, ์ฌ๋ฌ๋ถ์ ์ด์ ์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ๋ณต์กํ ํ๋ซํผ์์๋ ์์ ํ๊ณ ํจ์จ์ ์ธ ์ธ์ฆ ์์คํ ์ ๊ตฌ์ถํ ์ ์์ ๊ฑฐ์์. JWT๋ ํ๋ ์น ๊ฐ๋ฐ์์ ๋งค์ฐ ์ค์ํ ๊ธฐ์ ์ด๋ฉฐ, ์ฌ๋ฌ๋ถ์ด ์ด๋ฅผ ๋ง์คํฐํ๋ค๋ ๊ฒ์ ์ ๋ง ๋๋จํ ์ฑ๊ณผ์ ๋๋ค!
๐ก ๊ธฐ์ตํ์ธ์: JWT๋ ๊ฐ๋ ฅํ ๋๊ตฌ์ง๋ง, ๋ง๋ฅ ํด๊ฒฐ์ฑ ์ ์๋๋๋ค. ํญ์ ์ฌ๋ฌ๋ถ์ ํ๋ก์ ํธ ์๊ตฌ์ฌํญ์ ์ ์คํ ๊ณ ๋ คํ๊ณ , ํ์์ ๋ฐ๋ผ ๋ค๋ฅธ ์ธ์ฆ ๋ฐฉ์๊ณผ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์์.
์์ผ๋ก ์ฌ๋ฌ๋ถ์ด JWT๋ฅผ ํ์ฉํด ๋ฉ์ง ํ๋ก์ ํธ๋ค์ ๋ง๋ค์ด๋๊ฐ ๊ฑฐ๋ผ ๋ฏฟ์ด์. ํ์ง๋ง ๊ธฐ์ ์ ์ธ๊ณ๋ ๊ณ์ํด์ ๋ณํํ๊ณ ์์ด์. JWT๋ ์์ธ๋ ์๋์ฃ . ๊ทธ๋์ ํญ์ ์ต์ ๋ํฅ์ ์ฃผ์ํ๊ณ , ์๋ก์ด ๋ณด์ ์ํ์ ๋๋นํ๋ ๊ฒ์ด ์ค์ํด์.
๋ง์ง๋ง์ผ๋ก, ์ด ๊ธ์ ํตํด ๋ฐฐ์ด ๋ด์ฉ์ ์ค์ ๋ก ์ ์ฉํด๋ณด๋ ๊ฒ์ ์์ง ๋ง์ธ์. ์ง์ ์ฝ๋๋ฅผ ์์ฑํ๊ณ , ๋ค์ํ ์๋๋ฆฌ์ค๋ฅผ ํ ์คํธํด๋ณด๋ฉด์ ์ฌ๋ฌ๋ถ๋ง์ JWT ์ ๋ฌธ์ฑ์ ํค์๋๊ฐ์ธ์. ๊ทธ๋ฆฌ๊ณ ์ฌ๋ฌ๋ถ์ด ๋ง๋ ๋ฉ์ง ํ๋ก์ ํธ๋ค์ ์ธ์๊ณผ ๊ณต์ ํด์ฃผ์ธ์!
JWT์ ์ธ๊ณ๋ ๊ดํํ๊ณ ํฅ๋ฏธ์ง์งํด์. ์ด ์ฌ์ ์ด ์ฌ๋ฌ๋ถ์ ๊ฐ๋ฐ์ ๊ฒฝ๋ ฅ์ ํฐ ๋์์ด ๋๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ์์ผ๋ก๋ ๊ณ์ํด์ ๋ฐฐ์ฐ๊ณ , ์ฑ์ฅํ๊ณ , ํ์ ํด ๋๊ฐ์ธ์. ์ฌ๋ฌ๋ถ์ ๋ฏธ๋๋ ์ ๋ง ๋ฐ์ ๋ณด์ ๋๋ค! ๐
JWT์ ํจ๊ปํ๋ ์ฌ๋ฌ๋ถ์ ์ฝ๋ฉ ๋ผ์ดํ๊ฐ ์ฆ๊ฒ๊ณ ์์ฐ์ ์ด๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ํดํผ ์ฝ๋ฉ! ๐๐จโ๐ป๐ฉโ๐ป
- ์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์ฌ๋ฅ๋ท์ ์ต์ AI ๊ธฐ์ ๊ณผ ๋ฒ๋ฅ ์ ๊ธฐ๋ฐํ์ฌ ์์ฌ์ ์ง์ ์ฌ์ฐ๊ถ์ ์ ๊ทน์ ์ผ๋ก ๋ณดํธํ๋ฉฐ,
๋ฌด๋จ ์ฌ์ฉ ๋ฐ ์นจํด ํ์์ ๋ํด ๋ฒ์ ๋์์ ํ ๊ถ๋ฆฌ๋ฅผ ๋ณด์ ํฉ๋๋ค.
ยฉ 2025 ์ฌ๋ฅ๋ท | All rights reserved.
๋๊ธ 0๊ฐ