[Spring Security] JWT ์ƒ์„ฑ

ํ˜คยท2022๋…„ 11์›” 25์ผ
0

SpringSecurity

๋ชฉ๋ก ๋ณด๊ธฐ
10/13
post-thumbnail

์˜์กด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ถ”๊ฐ€

๐Ÿง Spring Framework์™€ ๊ด€๊ณ„๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€, JWT ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๋ณ„๊ฐœ์˜ ๊ฒƒ์œผ๋กœ ์„œ๋กœ ์—ฐ๊ด€๋˜์–ด ์žˆ์ง€ ์•Š์•„ ์‚ฌ์‹ค์ƒ Spring Framework์™€ ๊ด€๊ณ„๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋˜์–ด ์žˆ์ง€ ์•Š์•„๋„ JWT ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

JWT ์ƒ์„ฑ

JWT ์ƒ์„ฑ ๊ธฐ๋Šฅ ๊ตฌํ˜„

๐Ÿ“ ํ•ด์•ผํ•  ์ผ

  1. JWT๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ฒ€์ฆํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ์ •์˜
  2. ํด๋ž˜์Šค ๋‚ด๋ถ€์— JWT ์ƒ์„ฑ ๋ฉ”์„œ๋“œ ์ถ”๊ฐ€

1. JwtTokenizer ํด๋ž˜์Šค ์ •์˜

JwtTokenizer ํด๋ž˜์Šค๋Š” JWT(Json Web Token)์„ ์ƒ์„ฑํ•˜๊ณ  ๊ฒ€์ฆํ•˜๋Š” ์ผ์„ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์žŠ์ง€๋ง์ขŒ์ž์žใ…ใ…ˆใ…!

2. JWT ์ƒ์„ฑ ๋ฉ”์„œ๋“œ ๊ตฌํ˜„

์กฐ๊ฐ์กฐ๊ฐ ๋”ฐ๋‹ค๋‹ค-๐Ÿ‘Š

2-1. encodeBase64SecretKey(String secretKey)

๐Ÿ’กSecret Key๋ฅผ ์•”ํ˜ธํ™” ํ•˜๋Š” ๋ฉ”์„œ๋“œ

  1. Plain Text ํ˜•ํƒœ์ธ Secret Key๋ฅผ getBytes(StandardCharsets.UTF_8)๋กœ byte[]ํ™” ํ•œ๋‹ค.
    • StandardCharsets.UTF_8 : ํ•ด๋‹น ํ‘œ์ค€์œผ๋กœ ๋ฌธ์ž๋ฅผ ํ˜•์„ฑ
  2. byte[]ํ™” ๋œ Secret Key๋ฅผ Base64 ํ˜•์‹์˜ ๋ฌธ์ž์—ด๋กœ ์ธ์ฝ”๋”ฉํ•œ๋‹ค.

2-2. generateAccessToken()

๐Ÿ’ก์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ตœ์ดˆ๋กœ JWT๋ฅผ ๋ฐœ๊ธ‰ํ•ด์ฃผ๋Š” JWT ์ƒ์„ฑ ๋ฉ”์„œ๋“œ
ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ Payload(claims, subject, expiration, SecretKey)๋ฅผ ๋ฐ›๋Š”๋‹ค.

  1. getKeyFromBase64EncodedKey() : ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ฐ›์€ Base64 ํ˜•์‹์˜ Secret Key๋ฅผ ์ด์šฉํ•ด Key(Security Key) ๊ฐ์ฒด๋ฅผ ์–ป๋Š”๋‹ค.

  2. setClaims() : JWT์— ํฌํ•จ ์‹œํ‚ฌ Custom Claims๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
    - Custom Claims์—๋Š” ์ฃผ๋กœ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์™€ ๊ด€๋ จ๋œ ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.
    ๊ทธ ์™ธ์˜ ํด๋ ˆ์ž„ ์ถ”๊ฐ€๋Š” JWT ๊ธฐ๋ณธ ๊ฐœ๋… - payload ์ฐธ๊ณ ํ•  ๊ฒƒ

  3. signWith() : JWT์— ์„œ๋ช…์„ ์ €์žฅํ•˜๋Š” ๋ฉ”์„œ๋“œ๋กœ Secret Key๋กœ ์–ป์€ Key ๊ฐ์ฒด๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๊ฐ–๋Š”๋‹ค.

  4. compact() : JWT๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ง๋ ฌํ™”ํ•˜๋Š” ๋ฉ”์„œ๋“œ

2-3. generateRefreshToken()

๐Ÿ’กAccessToken์ด ๋งŒ๋ฃŒ๋˜์—ˆ์„ ๊ฒฝ์šฐ, ์žฌ๋ฐœ๊ธ‰์„ ๋‹ด๋‹นํ•˜๋Š” RefreshToken์„ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์„œ๋“œ
ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ Payload(subject, expiration, SecretKey)๋ฅผ ๋ฐ›๋Š”๋‹ค.

๐Ÿง ์™œ claims์€ ์—†์ง€?
RefreshToken์˜ ์—ญํ• ์€ ๋‹จ์ˆœํ•˜๊ฒŒ AccessToken ์žฌ๋ฐœ๊ธ‰! ์‚ฌ์šฉ์ž์™€ ๊ด€๋ จ๋œ ์ •๋ณด๋Š” AccessToken์ด ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ตณ์ด ์ด์ค‘์œผ๋กœ ๋‹ด์„ ํ•„์š”๊ฐ€ ์—†๋‹ค!

1-2. generateAccessToken()์™€ ์ค‘๋ณต๋˜๋Š” ๋‚ด์šฉ์ด๋ฏ€๋กœ ์ƒ๋žต!

2-4. getKeyFromBase64EncodedKey()

๐Ÿ’กJWT์˜ ์„œ๋ช…์— ์‚ฌ์šฉํ•  Secret Key๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์„œ๋“œ
ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ encodeBase64SecretKey() ๋ฉ”์„œ๋“œ๋กœ Base64 ํ˜•์‹์œผ๋กœ ์ธ์ฝ”๋”ฉ ๋œ Secret Key๋ฅผ ๋ฐ›๋Š”๋‹ค.

  1. ์ธ์ฝ”๋”ฉ๋œ Secret Key๋ฅผ ๋””์ฝ”๋”ฉํ•œ ํ›„, byte array๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  2. Keys.hmacShaKeyFor() : key byte array๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ์ ˆํ•œ HMAC ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ ์šฉํ•œ ํ›„ Key ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.

JWT ์ƒ์„ฑ ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ

๐Ÿ“ ํ•ด์•ผํ•  ์ผ

  1. JWT๋ฅผ ์ƒ์„ฑ ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•  ํด๋ž˜์Šค ์ •์˜
  2. ๊ฐ ๋ฉ”์„œ๋“œ ๋ณ„ ํ…Œ์ŠคํŒ… ์ฝ”๋“œ ์ž‘์„ฑ

1. JwtTokenizerTest ํด๋ž˜์Šค ์ •์˜

@TestInstance(TestInstance.Lifecycle.PER_CLASS)

๐Ÿ’กJUnit ํ…Œ์ŠคํŠธ์—์„œ ํ…Œ์ŠคํŠธ ์ธ์Šคํ„ด์Šค์˜ ์ƒ์„ฑ ๋‹จ์œ„๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ์• ๋„ˆํ…Œ์ด์…˜

๊ธฐ๋ณธ๊ฐ’์€ Lifecycle.PER_METHOD๋กœ ํ•ด๋‹น ์• ๋„ˆํ…Œ์ด์…˜์ด ๋ช…์‹œ๋˜์–ด ์žˆ์ง€ ์•Š์•„๋„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์ ์šฉ๋œ๋‹ค.
PER_METHOD : ํ…Œ์ŠคํŒ… ๋ฉ”์„œ๋“œ ๋ณ„๋กœ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.
PER_CLASS : ํ…Œ์ŠคํŒ… ํด๋ž˜์Šค ๋ณ„๋กœ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

๐Ÿง ๋ฌด์Šจ ์ฐจ์ด์ง€?
PER_METHOD๋Š” ๊ฐ๊ฐ์˜ ํ…Œ์ŠคํŠธ๊ฐ€ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋˜์–ด์•ผ ํ•  ๊ฒฝ์šฐ ์‚ฌ์šฉ๋˜๊ณ , ํ…Œ์ŠคํŠธ๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์ƒํƒœ ๊ฐ’์„ ๊ณต์œ ํ•˜๋ฉฐ ๋‹ค์Œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ๋Š” PER_CLASS๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

2. ํ…Œ์ŠคํŒ… ๋ฉ”์„œ๋“œ ๊ตฌํ˜„

2-1. @BeforeAll, init()

ํ…Œ์ŠคํŠธ์— ์‚ฌ์šฉํ•  Secret Key๋ฅผ Base64 ํ˜•์‹์œผ๋กœ ์ธ์ฝ”๋”ฉํ•œ ํ›„, ์ธ์ฝ”๋”ฉ ๋œ Secret Key๋ฅผ ๊ฐ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ์‚ฌ์šฉํ•˜๋„๋ก ํ•œ๋‹ค.

2-2. encodeBase64SecretKeyTest()

๐Ÿ’กPlain Text์ธ Secret Key๊ฐ€ Base64 ํ˜•์‹์œผ๋กœ ์ธ์ฝ”๋”ฉ์ด ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜๋Š”์ง€ ํ…Œ์ŠคํŠธ

Plain Text์˜ Secret Key์™€ ์ธ์ฝ”๋”ฉ ๋œ Secret Key๋ฅผ ๋””์ฝ”๋”ฉํ•œ ๊ฐ’์„ ๋น„๊ต ๊ฒ€์ฆํ•œ๋‹ค.

2-3. generateAccessTokenTest()

๐Ÿ’ก JwtTokenizer๊ฐ€ Access Token์„ ์ •์ƒ์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ

JWT๋Š” ์ƒ์„ฑํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ’์ด ๋ฐ”๋€Œ๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ๋œ AccessToken์ด null์ธ์ง€ ์•„๋‹Œ์ง€๋งŒ ๊ฒ€์ฆํ•œ๋‹ค.
๊ทธ ์™ธ์˜ ๋” ์ •ํ™•ํ•œ ํ…Œ์ŠคํŠธ๋Š” JWT์˜ ์„œ๋ช… ๊ฒ€์ฆ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

2-4. generateRefreshTokenTest()

๐Ÿ’ก JwtTokenizer๊ฐ€ Refresh Token์„ ์ •์ƒ์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ

generateAccessTokenTest()์™€ ๋™์ผํ•˜์—ฌ ๋‚ด์šฉ ์ƒ๋žต

๐Ÿ‘‹ ์—ฌ๊ธฐ๊นŒ์ง€ ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ํ†ต๊ณผ ๋œ๋‹ค๋ฉด JWT๋ฅผ ๊ฒ€์ฆํ•  ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค

profile
๐Ÿง‘โ€๐Ÿ’ป๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž, ์กฐ๊ธˆ์”ฉ ๊พธ์ค€ํ•˜๊ฒŒ

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