โœ๐Ÿป [Code Camp_TIL] 23์ผ์ฐจ: ๋กœ๊ทธ์ธ์˜ ์—ญ์‚ฌ, JWT ํ† ํฐ, Session Storage & Local Storage, Cookie

code_Jยท2023๋…„ 4์›” 22์ผ
0

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
29/41
post-thumbnail

๋กœ๊ทธ์ธ๊ณผ ์—ญ์‚ฌ ์ดํ•ด


์ฒซ ๋ฒˆ์งธ ๋ฐฉ์‹

๋กœ๊ทธ์ธ์„ ํ•˜๋ฉด ๋ฐฑ์—”๋“œ๋กœ ๋กœ๊ทธ์ธ api ์š”์ฒญ์ด ๋˜๊ณ , ๋ฐฑ์—”๋“œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ํšŒ์› ์ •๋ณด๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค. ๋งŒ์•ฝ ํšŒ์›์ •๋ณด์™€ ๋กœ๊ทธ์ธ ์ •๋ณด๊ฐ€ ์ผ์น˜ํ•˜๋ฉด ๋ฐฑ์—”๋“œ ์ปดํ“จํ„ฐ์— ๊ฐ์ฒด(Session)๋ฅผ ๋งŒ๋“ค์–ด๋†“๊ณ  ์ •๋ณด๋ฅผ ์ €์žฅํ•œ๋‹ค.

๊ทธ ํ›„์— ํŠน์ •ํ•œ ์„ธ์…˜ ์•„์ด๋””๋ฅผ ๋ถ€์—ฌํ•ด์„œ ๋ธŒ๋ผ์šฐ์ €๋กœ ๋ณด๋‚ด์ค€๋‹ค. ์ €์žฅ ์žฅ์†Œ๋กœ๋Š” state, ๋ณ€์ˆ˜, ๋ธŒ๋ผ์šฐ์ € ์ €์žฅ๊ณต๊ฐ„(local storage), session storage, ์ฟ ํ‚ค ๋“ฑ์ด ์žˆ๋‹ค.

๋กœ๊ทธ์ธ(์ธ์ฆ) ํ›„์— fetchUser์ฒ˜๋Ÿผ ํšŒ์›์ •๋ณด๋ฅผ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” http header์— ๋กœ๊ทธ์ธ ์ฆํ‘œ์ธ ์„ธ์…˜ ์•„์ด๋””๋ฅผ ๋ถ€์ฐฉํ•ด์„œ ๋ฐฑ์—”๋“œ๋กœ ๋ณด๋‚ด๊ฒŒ ๋œ๋‹ค(์ธ๊ฐ€). ๋ฐฑ์—”๋“œ์—์„œ๋Š” http header์— ์„ธ์…˜ ์•„์ด๋””๊ฐ€ ๋“ค์–ด์™€์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , session์— ์ •๋ณด๊ฐ€ ์žˆ๋Š”์ง€ ์ฒดํฌํ•œ๋‹ค. ๊ทธ ํ›„์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ฐ€์„œ ์š”์ฒญ๋ฐ›์€ ์ •๋ณด๋ฅผ ์ฐพ์•„์„œ ๋Œ๋ ค์ค€๋‹ค.

์ด ๋ฐฉ์‹์€ ์„ธ์…˜ ์•„์ด๋””๋ฅผ ํ†ตํ•ด ๋ณธ์ธ์ด ๋ˆ„๊ตฐ์ง€๋Š” ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์‚ฌ์šฉ์ž๊ฐ€ ๋งŽ์•„์ง€๋ฉด, session์— ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ๋ฉ”๋ชจ๋ฆฌ(RAM)์ด ๋ถ€์กฑํ•ด์ง„๋‹ค. ์ด๋ฅผ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ปดํ“จํ„ฐ์˜ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์—…๊ทธ๋ ˆ์ด๋“œ(scale-up)ํ•ด์ฃผ์—ˆ๋‹ค.


๋‘ ๋ฒˆ์งธ ๋ฐฉ์‹

๋ฐฑ์—”๋“œ ์ปดํ“จํ„ฐ์˜ ์„ฑ๋Šฅ์„ ์—…๊ทธ๋ ˆ์ด๋“œ ํ–ˆ์Œ์—๋„ ๋” ๋งŽ์€ ์œ ์ €์˜ ์ ‘์†์ด ๋™์‹œ๋‹ค๋ฐœ์ ์œผ๋กœ ์ผ์–ด๋‚˜๋ฉด, ์—ฌ์ „ํžˆ ์„œ๋ฒ„์˜ ๋ถ€ํ•˜๋ฅผ ์ดˆ๋ž˜ํ–ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋‚˜์˜จ ๊ฒƒ์ด scale-out(์ˆ˜ํ‰ํ™•์žฅ๋ฐฉ์‹)์ด๋‹ค. ๋ฐฑ์—”๋“œ ์ปดํ“จํ„ฐ๋ฅผ ์—ฌ๋Ÿฌ ๋Œ€ ๋งˆ๋ จํ•ด์„œ ๊ฐ™์€ ์„œ๋ฒ„๊ฐ€ ์‹คํ–‰๋˜๊ฒŒ๋” ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

ํ•˜์ง€๋งŒ ๋ฐฑ์—”๋“œ ์ปดํ“จํ„ฐ๋ฅผ ๋ณต์‚ฌํ•  ๋•Œ ์„ธ์…˜๊นŒ์ง€ scale out ๋˜์ง€ ์•Š์•„์„œ ๊ธฐ์กด์˜ ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋˜ ์ปดํ“จํ„ฐ๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ์ปดํ“จํ„ฐ์— ๊ฐ€๋ฉด ์„ธ์…˜ ํ…Œ์ด๋ธ”์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ฒŒ ๋˜์—ˆ๋‹ค.

์œ„์˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์„ธ์…˜ ํ…Œ์ด๋ธ”์„ ๊ฐ€์ ธ๋‹ค ๋†“์•˜๋‹ค. ํ•˜์ง€๋งŒ ์ด ์—ญ์‹œ๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์„ธ์…˜ ํ…Œ์ด๋ธ”์— ๋ถ€ํ•˜๊ฐ€ ์ง‘์ค‘๋˜์–ด์„œ ๋Š๋ ค์ง€๋Š” ๋ณดํ‹€๋„ฅ ํ˜„์ƒ์„ ์ผ์œผ์ผฐ๋‹ค!


์„ธ ๋ฒˆ์งธ ๋ฐฉ์‹

๋”ฐ๋ผ์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ชผ๊ฐœ๋Š” ๋ฐฉ๋ฒ•์„ ๊ณ ์•ˆํ•ด๋ƒˆ๋‹ค.

์ˆ˜์งํŒŒํ‹ฐ์…”๋‹ ํ˜น์€ ์ˆ˜ํ‰ํŒŒํ‹ฐ์…”๋‹(์ƒค๋”ฉ)์„ ํ†ตํ•ด ์ชผ๊ฐœ๊ณ , ์œ ์ € ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™”์„ ๋•Œ ํ•ด๋‹น ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์„ ํ™œ์šฉํ–ˆ๋‹ค. ๋‹ค๋งŒ ๋ฐ์ดํ„ฐ๋“ค์ด Disk์— ์ €์žฅ๋˜๋ฉด์„œ ์ธ๊ฐ€๋ฅผ ํ•  ๋•Œ์—๋Š” Disk IO๊ฐ€ ๋„ˆ๋ฌด ๋งŽ์ด ๋ฐœ์ƒํ•ด์„œ ์ฒ˜๋ฆฌ์†๋„๊ฐ€ ๋Š๋ ค์ง€๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ ๋‚˜์˜จ ๊ฒƒ์ด Redis์ด๋‹ค. Redis๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•ด๋‘๋Š” ์ž„์‹œ ๋ฐ์ดํ„ฐ ๋ฒ ์ด์Šค๋กœ, Redis์— sessioin table์„ ๋‘๊ณ , ์ธ๊ฐ€๋ฅผ ํ–ˆ์„ ๋•Œ์—๋Š” ๋ฐ”๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ ๊ฐ€๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ redis์˜ session table์—์„œ ๊ฒ€์ฆํ•˜๊ณ , ๋ณธ ์œ ์ € ๋ฐ์ดํ„ฐ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๊ฐ€์„œ ๊ฐ€์ ธ์˜จ๋‹ค. ์ด ๋ฐฉ์‹์ด ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹ ์ค‘ ํ•œ ๊ฐ€์ง€ ๋ฐฉ์‹์ด๋‹ค!


JWT ๋กœ๊ทธ์ธ

redis์—๋„ ์ ‘๊ทผํ•˜์ง€ ์•Š๋Š” ๋” ํšจ์œจ์ ์ธ ๋ฐฉ๋ฒ•์ด ์žˆ์„๊นŒ? ๋˜‘๋˜‘ํ•œ ๊ฐœ๋ฐœ์ž๋“ค์ด ๊ทธ๋Ÿฐ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ƒˆ๋‹ค!

๋ฐ”๋กœ, ์„ธ์…˜ ์•„์ด๋””๋ฅผ redis์— ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„œ ๋ฐฑ์—”๋“œ๋กœ ๊ฐ€์ ธ์˜จ ํ›„ ๊ฐ์ฒด๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋งŒ๋“ค์–ด ์•”ํ˜ธํ™”์‹œ์ผœ์„œ ์•”ํ˜ธํ™”๋œ ํ‚ค(accessToken)๋ฅผ ๋ธŒ๋ผ์šฐ์ €์— ๋Œ๋ ค์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

์•ก์„ธ์Šคํ† ํฐ์€ ๋ธŒ๋ผ์šฐ์ €์˜ state ๋“ฑ์— ์ €์žฅํ•ด ๋‘์—ˆ๋‹ค๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ๋ฐฑ์—”๋“œ๋กœ api ์š”์ฒญํ•  ๋•Œ ๋‹ค์‹œ ์•ก์„ธ์Šคํ† ํฐ์„ ๋ณด๋‚ด์„œ, ๋ฐฑ์—”๋“œ์—์„œ ๋ณตํ˜ธํ™”(์•”ํ˜ธ ํ•ด๋…)ํ•ด์„œ ์‚ฌ์šฉ์ž๋ฅผ ์‹๋ณ„ํ•œ ํ›„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฐฉ์‹์„ JWT(Json Web Token) ๋ฐฉ์‹์ด๋ผ๊ณ  ํ•œ๋‹ค. JWT ํ† ํฐ์€ ํ•ด๋‹น ํ† ํฐ์ด ๋ฐœ๊ธ‰ ๋ฐ›์•„์˜จ ์„œ๋ฒ„์—์„œ ์ •์ƒ์ ์œผ๋กœ ๋ฐœ๊ธ‰์„ ๋ฐ›์•˜๋‹ค๋Š” ์ฆ๋ช…์„ ํ•˜๋Š” signature๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์„œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์—ด์–ด๋ณด์ง€ ์•Š๊ณ ๋„ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฃผ์˜! JWT ํ† ํฐ์€ ์•ก์„ธ์Šคํ† ํฐ๊ณผ ๊ฐ™์€ ๊ฐœ๋…์ด ์•„๋‹ˆ๋‹ค.

JWT ํ† ํฐ

JWT ๋ฐฉ์‹์—์„œ ์•ก์„ธ์Šคํ† ํฐ์„ ์ €์žฅํ•˜๋Š” ์žฅ์†Œ๋Š” ๋ณ€์ˆ˜, ์„ธ์…˜ ์Šคํ† ๋ฆฌ์ง€, ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€, ์ฟ ํ‚ค ๋“ฑ์ด ์žˆ๋‹ค.

  • ๋ณ€์ˆ˜: ์ƒˆ๋กœ๊ณ ์นจ ์‹œ ์‚ญ์ œ(์ดˆ๊ธฐํ™”)
  • Session Storage: ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๊ป๋‹ค ํ‚ค๋ฉด ์ดˆ๊ธฐํ™”
  • Local Storage: ๋ธŒ๋ผ์šฐ์ € ๊ป๋‹ค ์ผœ๋„ ๋‚จ์•„์žˆ์Œ
  • ์ฟ ํ‚ค: ๋ธŒ๋ผ์šฐ์ € ๊ป๋‹ค ์ผœ๋„ ๋‚จ์•„์žˆ์Œ. ๋งŒ๋ฃŒ์‹œ๊ฐ„ ๋ถ€์—ฌ ๊ฐ€๋Šฅ(๋งŒ๋ฃŒ์‹œ๊ฐ„ ๋„˜์œผ๋ฉด ์ž๋™ ์‚ญ์ œ). ๋ณด์•ˆ๊ธฐ๋Šฅ(httpOnly, Secure ๋“ฑ) ๊ฐ•ํ™” ๊ฐ€๋Šฅ, ์„œ๋ฒ„์™€ ์—ฐ๋™์ด ๊ฐ€๋Šฅ(์ž๋™์œผ๋กœ ์„œ๋ฒ„์™€ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์™”๋‹ค๊ฐ”๋‹ค ํ•  ์ˆ˜ ์žˆ์Œ)

๋˜ํ•œ, JWT ํ† ํฐ์€ ์•ˆ์— ๋‚ด์šฉ์ด ๋‹ค ๋ณด์ด๋Š” ํ† ํฐ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์ค‘์š”ํ•œ ๋‚ด์šฉ์€ JWT ํ† ํฐ ์•ˆ์— ์ €์žฅํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค! JWT ํ† ํฐ์€ ๋‚ด์šฉ์„ ๊ฐ์ถ˜๋‹ค๊ธฐ๋ณด๋‹ค๋Š”, ๋‚ด์šฉ ์กฐ์ž‘์„ ๊ธˆ์ง€ํ•œ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋˜๋Š” ๊ฒƒ ์•„๋‹Œ๊ฐ€? ๋ณด์•ˆ์„ ์œ„ํ•ด์„œ ํ† ํฐ ๋งŒ๋ฃŒ์‹œ๊ฐ„์„ ์งง๊ฒŒ ์ฃผ์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์กฐ์ž‘์„ ๋ฏธ์—ฐ์— ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด signature(ํ† ํฐ์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋‚ด์šฉ ์กฐ์ž‘์„ ์œ„ํ•ด์„œ๋Š” ์ด ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•Œ์•„์•ผ ํ•œ๋‹ค. ํ•ด๋‹น ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋ฐฑ์—”๋“œ์—์„œ ์ƒ์„ฑํ•˜๋ฉฐ, ์•Œ ์ˆ˜ ์—†๋‹ค.


๋ณตํ˜ธํ™”๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•œ ์•”ํ˜ธํ™”(ํšŒ์›๊ฐ€์ž…)


๋‹จ๋ฐฉํ–ฅ ์•”ํ˜ธํ™”(ํ•ด์‹ฑ)์™€ ์–‘๋ฐฉํ–ฅ ์•”ํ˜ธํ™”

๋กœ๊ทธ์ธ์„ ํ•˜๊ณ , ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ fetch ํ•ด์™”์„ ๋•Œ ๋ธŒ๋ผ์šฐ์ €์— ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ fetchํ•  ์ˆ˜ ์—†์–ด์•ผ ํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์žˆ๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜ ์—†๊ฒŒ ํ•ด๋†“์•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด๋Ÿฌํ•œ ๋ฏผ๊ฐ ์ •๋ณด๋“ค์€ ๋ฐฑ์—”๋“œ์— ์ €์žฅํ•  ๋•Œ ๊ทธ๋Œ€๋กœ ์ €์žฅํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค. ํ•ดํ‚น์˜ ์œ„ํ—˜์„ฑ์ด ์žˆ๋‹ค.


์–‘๋ฐฉํ–ฅ ์•”ํ˜ธํ™”

JWT ๋ฐฉ์‹์ฒ˜๋Ÿผ ๋ณตํ˜ธํ™”๊ฐ€ ๋˜๋Š” ์•”ํ˜ธํ™”. ์•”ํ˜ธํ™”์™€ ๋ณตํ˜ธํ™” ๋ชจ๋‘ ๊ฐ€๋Šฅ


๋‹จ๋ฐฉํ–ฅ ์•”ํ˜ธํ™”(hash)

์•”ํ˜ธํ™”๋Š” ๋˜์ง€๋งŒ ๋ณตํ˜ธํ™”๋Š” ์•ˆ๋œ๋‹ค. ๋‹ค๋Œ€์ผ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ด์„œ ์›๋ž˜ ์ •๋ณด๋ฅผ ์•Œ์•„๋‚ด๊ธฐ ์–ด๋ ต๋„๋ก ํ•ด๋†“๋Š”๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ๋Ÿผ์—๋„ ๋ฌด์ฐจ๋ณ„๊ณต๊ฒฉ์œผ๋กœ ํ•ดํ‚น ์œ„ํ—˜์ด ์žˆ์„ ์ˆ˜ ์žˆ์–ด์„œ ์ตœ๊ทผ์—๋Š” Bcrypt Hash๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™”ํ•œ๋‹ค.


ํ† ํฐ ๋ณด๋‚ด๊ธฐ

HTTP HEADERS์— "Authorization"์„ ๋ณด๋‚ด์ฃผ๋ฉด ๋œ๋‹ค. Bearer๋Š” ๊ด€๋ก€์ƒ ์‚ฌ์šฉํ•  ๋ฟ ํ•„์ˆ˜๋กœ ์ ์–ด์ค˜์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ด ๋ถ€๋ถ„์€ ๋ฐฑ์—”๋“œ์™€ ์ƒ์˜ํ•ด์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.


JWT ํ† ํฐ๊ณผ ์กฐ์ž‘ ๊ฐ€๋Šฅ์„ฑ

์ด์ œ ํšŒ์›๊ฐ€์ž…์„ ๋จผ์ € ํ•œ ํ›„์— ๊ทธ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์‹ค์ œ ๋กœ๊ทธ์ธ์„ ํ•ด๋ณด์•˜๋‹ค. ๋กœ๊ทธ์ธ์„ ํ•˜๋ฉด accessToken์„ ๋ฐ›์•„์˜ค๋Š”๋ฐ, ๋ฐ›์•„์˜จ accessToken์—๋Š” ์œ ์ €๊ฐ€ ๋กœ๊ทธ์ธ์„ ํ•œ ๊ธฐ๋ก์ด ์ €์žฅ๋˜์–ด ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ์œ ์ €์ •๋ณด๋ฅผ ํ™•์ธํ•ด์•ผ ํ•˜๋Š” API๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, accessToken์„ ์ฒจ๋ถ€ํ•ด์„œ ๋ณด๋‚ด๋ฉด ๋ฐฑ์—”๋“œ์—์„œ ์œ ์ €์ •๋ณด๋ฅผ ํ™•์ธํ•œ ํ›„์— ํ•ด๋‹น API๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.


JWT ํ† ํฐ์˜ ์กฐ์ž‘ ๊ฐ€๋Šฅ์„ฑ


JWT ํ† ํฐ์€ ๋ˆ„๊ตฌ๋“ ์ง€ ๋ณตํ˜ธํ™”๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค!?

jwt.io ์— ์ ‘์†ํ•ด์„œ Encoded(์•”ํ˜ธํ™”) ๋ถ€๋ถ„์— ์œ„์—์„œ ๋ฐ›์•„์˜จ accessToken์„ ๋„ฃ์œผ๋ฉด Decoded(๋ณตํ˜ธํ™”) ๋ถ€๋ถ„์— ํ† ํฐ์— ๋Œ€ํ•œ ์ •๋ณด๊ฐ€ ๋ชจ๋‘ ๋ณด์ธ๋‹ค.

๋งŒ์•ฝ ๋ˆ„๊ตฐ๊ฐ€ ํ† ํฐ์„ ์•Œ์•„๋‚ด์„œ ํ•ด๋‹น ์‚ฌ์ดํŠธ์— ๋„ฃ์–ด๋ณธ๋‹ค๋ฉด ํ† ํฐ์˜ ์ •๋ณด๋ฅผ ์‰ฝ๊ฒŒ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค! ๋”ฐ๋ผ์„œ ์ค‘์š”ํ•œ ๋ฐ์ดํ„ฐ๋Š” JWT ํ† ํฐ์— ์ €์žฅํ•˜๋ฉด ์•ˆ๋œ๋‹ค.


ํ† ํฐ ๋งŒ๋ฃŒ์‹œ๊ฐ„์„ ์งง๊ฒŒ ์คฌ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด JWT ํ† ํฐ์€ ๋ณด์•ˆ์ด ์ „ํ˜€ ์•ˆ๋˜๋Š” ๊ฒƒ ์•„๋‹Œ๊ฐ€..? ๊ทธ๋ ‡์ง€๋Š” ์•Š๋‹ค. JWT ํ† ํฐ์€ ํ† ํฐ์˜ ๋งŒ๋ฃŒ์‹œ๊ฐ„์„ ์งง๊ฒŒ ์ค€๋‹ค.

ํ•˜์ง€๋งŒ Decoded ์ •๋ณด์— ํ† ํฐ์˜ ๋งŒ๋ฃŒ์‹œ๊ฐ„์ด ๋ช…์‹œ๋˜์–ด ์žˆ์–ด์„œ ์ด๊ฒƒ ๋˜ํ•œ ์กฐ์ž‘์ด ๊ฐ€๋Šฅํ•˜๋‹ค.


JWT signature

ํ† ํฐ ๋งŒ๋ฃŒ์‹œ๊ฐ„๊นŒ์ง€ ์กฐ์ž‘์ด ๊ฐ€๋Šฅํ•˜๋ฉด ์–ด๋–กํ•˜๋‚˜ ์‹ถ์€๋ฐ, ์ด๋Ÿฐ ์กฐ์ž‘์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ JWT๋Š” signature(ํ† ํฐ์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

ํ† ํฐ์˜ ๋‚ด์šฉ์„ ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ํ† ํฐ์˜ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์•Œ์•„์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋ฐฑ์—”๋“œ์—์„œ ์ƒ์„ฑํ•˜๊ณ , ์šฐ๋ฆฌ๋Š” ์•Œ ์ˆ˜ ์—†๋‹ค.



๋กœ๊ทธ์ธ๊ณผ Recoil ์—ฐ๊ฒฐ


  1. ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ
// login page
import {useMutation,gql} from "@apollo/client"
import {ChangeEvent} from "react"

cosnt LOGIN_USER = gql`
	mutation loginUser($email:String){
		loginUser(email: $email, password: $password){
			accessToken
		}
	}
`

export default function LoginPage(){
	const [email,setEmail]=useState("")
	const [password,setPassword]=useState("")
	const [loginUser] = useMutation<Pick<IMutation,'loginUser'>,IMutationLoginUserArgs>(LOGIN_USER)
// loginUser ํƒ€์ž… ์ถ”๋ก  ๋ถˆ๊ฐ€๋Šฅ -> ์•ž์—๋Š” ๋ฐ›์•„์˜ฌ ํƒ€์ž…์„, ๋’ค์—๋Š” ๋ณด๋‚ด์ค„ ํƒ€์ž… ์ž‘์„ฑ

	const onChangeEmail = (event:ChangeEvent<HTMLInputElement>)=>{
		setEmail(event.target.value)
		}
	const onChangePassword = (event:ChangeEvent<HTMLInputElement>)=>{
    setPassword(event.target.value)
		}

	const onClickLogin = async()=>{
	try{
		cosnt result = await loginUser({
			variables:{
					email : email,
					password : password
				}
			})
		const accessToken = result.data?.loginUser.accessToken
		}catch(error){
			Modal.error({content : error.message})
		}
	} 

	return(
		<div>
			์ด๋ฉ”์ผ : <input type="text" onchange={onChangeEmail}/> <br/>
			๋น„๋ฐ€๋ฒˆํ˜ธ : <input type="password" onchange={onChangePassword}/> 
			<button onClick={onClickLogin}>๋กœ๊ทธ์ธํ•˜๊ธฐ!!</button>
		</div>
	)
}

  1. accessToken์„ global state(Recoil)์— ์ €์žฅํ•˜๊ธฐ

์œ ์ €์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์˜ค๋Š” api๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด http header ๋ถ€๋ถ„์— accessToken ์ฒจ๋ถ€ํ•ด์„œ ์š”์ฒญํ•ด์•ผ ํ•œ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ ๋ฐ ์ˆ˜์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

import { useRecoilState } from "recoil";

export default function LoginPage(){
	const [accessToken, setAccessToken] = useRecoilState(accessTokenState)
    
    const onClickLogin = async() => {
    try{
      const result = await loginUser({
      variables: {
      email: email,
       password: password
      }
      })
      const accessToken = result.data?.loginUser.accessToken
      setAccessToken(accessToken)
      router.push(`/loginsuccess`)
    } catch(error) {
    Modal.error({content: error.message})
    }
    }
}

  1. ๋กœ๊ทธ์ธ ์„ฑ๊ณต ํŽ˜์ด์ง€ ๋งŒ๋“ค๊ธฐ
// loginsuccess page
const FETCH_USER_LOGGED_IN = gql`
query fetchUserLoggedIn{
	fetchUserLoggedIn{
		email
		name
		}
	}
`
export default function LoginSuccessPage(){
	const {data} = useQuery<Pick<IQuery,"fetchUserLoggedIn">>(FETCH_USER_LOGGED_IN)

	return(
		<div>
			{data?.fetchUserLoggedIn.name}๋‹˜ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค.
		</div>
	)
}

  1. global state์— ์ €์žฅ๋œ accessToken์„ header์™€ ์—ฐ๋™ํ•˜๊ธฐ
//app.tsxํŒŒ์ผ
function MyApp({ component,pageProps }:AppProps){
const [accessToken,setAccessToken] = useState("")
const uploadLink = createUploadLink({
		uri : "๋ฐฑ์—”๋“œ ์ฃผ์†Œ",
		headers : { Authorization : `Bearer ${accessToken}` }
	})

	return (
			<ApolloProvider client={client}>
				<Component {..pageProps}/>
			</ApolloProvider>
	)
}

uploadLink์— ํ† ํฐ์„ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์จ ๋ชจ๋“  ์ปดํฌ๋„ŒํŠธ์—์„œ ๋กœ๊ทธ์ธ ๊ด€๋ จ ํ† ํฐ์„ ์ถ”๊ฐ€ํ•ด์„œ ๋ณด๋‚ด์ฃผ๋„๋ก ๋งŒ๋“ค์—ˆ๋‹ค.

๋กœ๊ทธ์ธ์„ ํ•œ ์‚ฌ๋žŒ๋งŒ ํ† ํฐ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ฒŒ ๋œ๋‹ค. ์œ„์— ํ† ํฐ ์ž๋ฆฌ์— ํ† ํฐ์„ ์ฑ„์šฐ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?

Recoil์— accessToken์„ ์ €์žฅํ•ด๋‘๊ณ  ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ์ปดํฌ๋„ŒํŠธ ์ „์ฒด๋ฅผ ๊ฐ์‹ธ์ฃผ๊ณ  ํ•„์š”ํ•œ ๊ณณ์—์„œ ๊บผ๋‚ด์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค!

//app.tsxํŒŒ์ผ
import { RecoilRoot } from "recoil";

function MyApp({ component,pageProps }:AppProps){

	return (
		<RecoilRoot>
        <ApolloSetting>
          <Global styles={globalStyles} />
          <Layout>
            <Component {...pageProps} />
          </Layout>
        </ApolloSetting>
      </RecoilRoot>
	)
}

๊ธฐ์กด์— app.tsx์—์„œ apollo setting ํ•ด์คฌ๋˜ ๋ถ€๋ถ„์€ ๋”ฐ๋กœ ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ๋ถ„๋ฆฌํ–ˆ๋‹ค.

// Apollo Setting ๋นผ์ฃผ๊ธฐ
import { useRecoilState } from "recoil";
import { accessTokenState } from "../../../commons/store";

export default function ApolloSetting(props) {
	const [accessToken,setAccessToken] =useRecoilState(accessTokenState)

	const uploadLink = createUploadLink({
			uri : "๋ฐฑ์—”๋“œ ์ฃผ์†Œ",
			headers : { Authorization : "Bearer ๋ฐ›์•„์˜จ ํ† ํฐ" }
		})

	return (
		<ApolloProvider client={client}>
			{props.children}
		</ApolloProvider>
	)
}


profile
Web FE ๊ฐœ๋ฐœ์ž ์ทจ์ค€์ƒ

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