๐ŸŒŸ [SEB FE] Section 3_ํšŒ๊ณ 

๊ฐ•์„ฑ์ผยท2023๋…„ 7์›” 8์ผ
0
post-thumbnail

๐Ÿ’ฌ ์žก๋‹ด


์ €๋ฒˆ ์ฃผ๋ถ€ํ„ฐ ์ด๋ฒˆ ์ฃผ๊นŒ์ง€ ๋ฐฐ์šด ๋‚ด์šฉ์€ ๋ชจ๋‘ ๋ฐฑ์—”๋“œ ๊ด€๋ จ์ด์—ˆ๋‹ค.

์„œ๋ฒ„ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ ๋‹น์‹œ ์ด ์ฑ•ํ„ฐ๋งŒ ๋„˜๊ธฐ๋ฉด ๋‹ค์‹œ ํ”„๋ก ํŠธ๋ฅผ ๋ฐฐ์šฐ์ง€ ์•Š์„๊นŒ?
ํ•˜๋Š” ์ƒ๊ฐ์ด ์žˆ์—ˆ์ง€๋งŒ ์ •์‹  ์ฐจ๋ ค๋ณด๋‹ˆ ๋”์šฑ๋” ์‹ฌํ™”์ ์ธ ๋ฐฑ์—”๋“œ๋ฅผ ๋ฐฐ์šฐ๊ณ  ์žˆ์—ˆ๋‹ค.

ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹...
๋‚˜์˜์ง€๋Š” ์•Š์ง€๋งŒ, ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ๋นจ๋ฆฌ ๋ฐฐ์šฐ์ง€ ์•Š์œผ๋ฉด ๊ฐ๋„ ์žƒ์–ด๋ฒ„๋ฆด ๊ฒƒ ๊ฐ™์•˜๊ณ 
๋ฌด์—‡๋ณด๋‹ค ์ด๋Ÿฌ๋‹ค๊ฐ€ ๊ทธ๋ƒฅ ํ’€์Šคํ…์„ ํ•ด๋ฒ„๋ฆฌ๋Š” ๊ฑฐ ์•„๋‹ˆ์•ผ? ํ•˜๋Š” ์“ธ๋ฐ์—†๋Š” ๊ฑฑ์ •๋„ ๋Š˜์—ˆ๋‹ค.

๋…ธ๋งˆ๋“œ์ฝ”๋” Next.JS ๊ฐ•์˜๋„ ๊ดœ์Šค๋ž˜ ๋“ฃ๊ณ  ์žˆ๋˜ 2์ฃผ์˜€๋‹ค.

๊ทธ๋™์•ˆ ์„ค๋ ์„ค๋  ์ง„ํ–‰ํ–ˆ๋˜ ๊ฒƒ์€ ์•„๋‹ˆ๋ฏ€๋กœ, ์ˆ˜์—… ๋“ค์œผ๋ฉด์„œ ๋‚จ๊ฒจ๋†จ๋˜
์„ธ์„ธํ•œ ๊ธฐ๋ก๋“ค์„ ์ด์ œ ํ’€์–ด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค! ํ›„์šฐ ๐Ÿ’จ๐Ÿ’จ



๐Ÿ”ฅ Review


๐Ÿช Cookie


๊ธฐ๋Šฅ ๊ตฌํ˜„ํ•˜๊ธฐ

  1. ํด๋ผ์ด์–ธํŠธ : ์„œ๋ฒ„๋กœ ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ
    a. ์•„์ด๋””, ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์„œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•œ๋‹ค.

  2. ์„œ๋ฒ„ : ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ
    a. ์š”์ฒญ์œผ๋กœ ์ „๋‹ฌ๋ฐ›์€ ์•„์ด๋””์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํšŒ์›๊ฐ€์ž…์ด ๋˜์–ด์žˆ๋Š” ์ •๋ณด์ธ์ง€ ํ™•์ธํ•œ๋‹ค.
    b. ํšŒ์›์ด๋ผ๋ฉด, ์‘๋‹ต์— ์ฟ ํ‚ค์™€ ํšŒ์› ์ •๋ณด๋ฅผ ๋‹ด์•„ ์ „๋‹ฌํ•œ๋‹ค.

  3. ํด๋ผ์ด์–ธํŠธ : ์‘๋‹ต์„ ๋ฐ›์•„ React ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ

  4. ํด๋ผ์ด์–ธํŠธ : ํ™”๋ฉด ๋ฆฌ๋ Œ๋”๋ง โ†’ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์œผ๋กœ ๋งˆ์ดํŽ˜์ด์ง€ ํ‘œ์‹œ
    ๋งŒ์•ฝ ๋กœ๊ทธ์ธํ•  ๋•Œ โ€˜๋กœ๊ทธ์ธ ์œ ์ง€โ€™ ์˜ต์…˜์„ ์„ ํƒํ–ˆ๋‹ค๋ฉด, ํ•ด๋‹น ํŽ˜์ด์ง€์— ์žฌ์ ‘์†ํ•  ๋•Œ ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•  ํ•„์š” ์—†์ด ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์˜จ ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํšŒ์› ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
    ๋กœ๊ทธ์•„์›ƒ์„ ์ผ๋ถ€๋Ÿฌ ํ•˜์ง€ ์•Š๋Š” ์ด์ƒ, ์ฟ ํ‚ค ์œ ์ง€ ์‹œ๊ฐ„๋งŒํผ ์ž๋™ ๋กœ๊ทธ์ธ์ด ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

  5. ํด๋ผ์ด์–ธํŠธ : ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์„œ๋ฒ„์— ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ ๋ณด๋‚ด๊ธฐ

  6. ์„œ๋ฒ„ : ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ ์ฒ˜๋ฆฌ
    a. ์ฟ ํ‚ค๋ฅผ ์‚ญ์ œํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ๋กœ ์‘๋‹ต์„ ๋ณด๋‚ธ๋‹ค.

  7. ํด๋ผ์ด์–ธํŠธ : ์‘๋‹ต์ด ์ž˜ ๋Œ์•„์˜ค๋ฉด React ์ƒํƒœ ์ดˆ๊ธฐํ™”

  8. ํด๋ผ์ด์–ธํŠธ : ํ™”๋ฉด ๋ฆฌ๋ Œ๋”๋ง โ†’ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์œผ๋กœ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€ ํ‘œ์‹œ



์ฟ ํ‚ค๋กœ ๋กœ๊ทธ์ธ ์œ ์ง€ ๊ตฌํ˜„ํ•˜๊ธฐ


1. ํด๋ผ์ด์–ธํŠธ : ์„œ๋ฒ„๋กœ ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ

  • ํด๋ผ์ด์–ธํŠธ์˜ Login.js ํŒŒ์ผ์„ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

    • ์ƒํƒœ๊ฐ€ 3๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

      • input์ฐฝ์— ์•„์ด๋””, ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์—…๋ฐ์ดํŠธ๋˜๋Š” loginInfo
      • ๋กœ๊ทธ์ธ ์œ ์ง€ํ•˜๊ธฐ ์ฒดํฌ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•˜๋Š” checkedKeepLogin
      • ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋ฐ‘์— ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋ฅผ ํ‘œ์‹œํ•˜๋Š” errorMessage
  • ์ผ๋‹จ ์•„์ด๋””, ๋น„๋ฐ€๋ฒˆํ˜ธ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ž…๋ ฅ์ด ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์—๋Ÿฌ๋ฅผ ๋„์šฐ๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ์ค๋‹ˆ๋‹ค.

  • const loginRequestHandler = () => {
    
    	if (!loginInfo.userId || !loginInfo.password) {
    	      setErrorMessage('์•„์ด๋””์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”')
    				// ์ž…๋ ฅ๋˜์ง€ ์•Š์€ ๊ฐ’์ด ์žˆ๋Š”๊ฑฐ๋‹ˆ๊นŒ ์š”์ฒญ์„ ๋ณด๋‚ด๋ณผ ํ•„์š”๋„ ์—†์ด ๋ฐ”๋กœ ๋ฆฌํ„ดํ•ด์ค๋‹ˆ๋‹ค.
    				return;
    	}
    
    	...
    }
    
  • Axios ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ, ๋กœ๊ทธ์ธ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ž…๋ ฅํ•ด ์ค๋‹ˆ๋‹ค. โ†’ "http://localhost:4000/login"

    • ์ด ์—”๋“œํฌ์ธํŠธ๋กœ ์–ด๋–ค ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‚ด์ค˜์•ผ ํ• ๊นŒ์š”? ์„œ๋ฒ„์˜ login.js๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”.
      • req.body์—์„œ loginInfo, checkedKeepLogin๋ฅผ ํ™•์ธํ•˜๊ณ  ์žˆ์œผ๋‹ˆ Login.js์˜ ์ƒํƒœ๋ฅผ ๊ทธ๋Œ€๋กœ ์‹ค์–ด์„œ ๋ณด๋‚ด์ค์‹œ๋‹ค.
      • req.body๋Š” ์–ด๋–ป๊ฒŒ ๋ณด๋‚ด๋‚˜์š”? Axios๋กœ post ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ์—๋Š” ์—”๋“œํฌ์ธํŠธ ๋‹ค์Œ ์ธ์ž๋กœ ๋„ฃ์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
      • .post("http://localhost:4000/login", {loginInfo, checkedKeepLogin})
  • ์„œ๋ฒ„์—์„œ ์š”์ฒญ์„ ์ž˜ ๋ฐ›์•„์˜ค๋Š”์ง€ ํ™•์ธํ•ด ๋ด…์‹œ๋‹ค. (npm start๋กœ ์„œ๋ฒ„๋ฅผ ์—ด์–ด๋†“์•„์•ผ ์ œ๋Œ€๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)

    • ์„œ๋ฒ„์˜ login.js์— console.log(req.body)๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ์ €์žฅํ•œ ๋‹ค์Œ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋ณด์„ธ์š”.
    • ์„œ๋ฒ„ ํ„ฐ๋ฏธ๋„์—์„œ ์•„๋ž˜ ์ด๋ฏธ์ง€์™€ ๊ฐ™์ด ๋ฐ›์•„์˜จ ์ •๋ณด๊ฐ€ ๋œฌ๋‹ค๋ฉด ์š”์ฒญ์„ ์ž˜ ๋ฐ›์•„์˜ค๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • ์š”์ฒญ์ด ์ž˜ ๋“ค์–ด์™”๋‹ค๋ฉด, ๋“ค์–ด์˜จ ์ •๋ณด๋ฅผ ํ™œ์šฉํ•˜์—ฌ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•œ ๋‹ค์Œ ์‘๋‹ต์„ ๋ณด๋‚ด์ฃผ๋„๋ก ํ•ฉ์‹œ๋‹ค.


๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

204 ์š”์ฒญ๊นŒ์ง€ ์ž˜ ๋œจ๊ณ , req.body๊นŒ์ง€ ์ •์ƒ์ ์œผ๋กœ ๋œจ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์•„์ง์€ ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•„์„œ, ๋งˆ์ดํŽ˜์ด์ง€ ํ™”๋ฉด์— ์ด๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.


2. ์„œ๋ฒ„ : ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ

โš™๏ธ /login.js


  • ํŒŒ์ผ ์•ˆ์— ์ž‘์„ฑ๋œ ์ฃผ์„์„ ๋”ฐ๋ผ์„œ ๋กœ์ง์„ ์ฐจ๊ทผ์ฐจ๊ทผ ์ž‘์„ฑํ•ด ๋ด…์‹œ๋‹ค. ์ผ๋‹จ userInfo๋ผ๋Š” ๋ณ€์ˆ˜๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„๋ณผ๊นŒ์š”?

  • const userInfo = {
        ...USER_DATA.filter((user) => user.userId === userId && user.password === password)[0],
      };
    • sever/db/data.js ์—์„œ ๊ฐ€์ ธ์˜จ ์ •๋ณด๋ฅผ ํ•„ํ„ฐ๋งํ•ด์„œ req.body๋กœ ๋“ค์–ด์˜จ ์•„์ด๋””, ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ์ผ์น˜ํ•˜๋Š” ์œ ์ € ์ •๋ณด๋งŒ ๋‚จ๊ธฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ง์ ‘ ํ™•์ธํ•ด ๋ณผ๊นŒ์š”? console.log(userInfo)๋ฅผ ์ถ”๊ฐ€๋กœ ์ž‘์„ฑํ•œ ํ›„์— ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ๋ณด๋‚ด๋ณด์„ธ์š”.

    • ์ผ์น˜ํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ์œ ์ € ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ์„œ ๋“ค์–ด์˜ต๋‹ˆ๋‹ค. ์—†์œผ๋ฉด ๋นˆ๊ฐ์ฒด๊ฐ€ ๋“ค์–ด์˜ต๋‹ˆ๋‹ค. ์š”์ฒญ์œผ๋กœ ๋“ค์–ด์˜ค๋Š” ๊ฐ’์— ๋”ฐ๋ผ ์กฐ๊ฑด๋ฌธ์œผ๋กœ ๋ถ„๊ธฐํ•˜์—ฌ ๊ฐ๊ฐ ๋‹ค๋ฅธ ์‘๋‹ต์„ ๋ณด๋‚ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.
      • userInfo๊ฐ€ ๋นˆ ๊ฐ์ฒด๋ผ๋ฉด? ๋กœ๊ทธ์ธ์ด ์‹คํŒจํ–ˆ๋‹ค๋Š” ์‘๋‹ต์„ ๋ณด๋‚ด์ค์‹œ๋‹ค.
        • ์ด๋•Œ. if (userInfo === undefined)๋กœ ๋ถ„๊ธฐํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค.
          • ๋นˆ ๊ฐ์ฒด๋„ ์ฃผ์†Œ ๊ฐ’์„ ๊ฐ€์ง€๋ฏ€๋กœ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
        • userInfo์— ์•„๋ฌด ํ‚ค๋‚˜ ์ฐ์–ด์„œ ๋ถ„๊ธฐํ•ด ์ฃผ์„ธ์š”. ๋‹ค์Œ ์ฝ”๋“œ๋Š” ์ฒซ ๋ฒˆ์งธ๋กœ ๋“ค์–ด์˜ค๋Š” ์œ ์ € ์ •๋ณด์˜ id๋กœ ๋ถ„๊ธฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
        • if (userInfo.id === undefined) { ... }
  • ๋กœ๊ทธ์ธ ์‹คํŒจ ์‘๋‹ต ์ฝ”๋“œ๋Š” ๊ตฌ์ฒด์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ์ž‘์„ฑํ•˜๋ฉด ์ข‹์„๊นŒ์š”? ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

  • // ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค์— ๋งž์ถฐ์„œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ์ค๋‹ˆ๋‹ค.
    if (userInfo.id === undefined) {
    	res.status(401).send('Not Authorized')
    } 
  • ๋กœ๊ทธ์ธ์— ์„ฑ๊ณตํ•œ๋‹ค๋ฉด, ํด๋ผ์ด์–ธํŠธ์— ์ฟ ํ‚ค๋ฅผ ์ „์†กํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฃผ์„์„ ์ฝ์–ด๋ณด๋‹ˆ cookieId์— userInfo.id๋ฅผ ๋‹ด์•„์•ผ ํ•œ๋‹ค๊ณ  ์„ค๋ช…๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

    • Express ์„œ๋ฒ„์—์„œ ์ฟ ํ‚ค ๋ณด๋‚ด๊ธฐ ์œ„ํ•ด์„œ๋Š”, res.cookie ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    • res.cookie ๋ฉ”์„œ๋“œ๋Š” ์ „๋‹ฌ์ธ์ž๋กœ ์ฟ ํ‚ค ์ด๋ฆ„, ์ฟ ํ‚ค ๊ฐ’, ์ฟ ํ‚ค ์˜ต์…˜์„ ๋ฐ›์Šต๋‹ˆ๋‹ค.
  • ์—ฌ๊ธฐ์„œ ์ฟ ํ‚ค ์˜ต์…˜์€ ๊ฐœ๋…ํ•™์Šต์—์„œ ๋ฐฐ์šด ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค. (๋งํฌ) ๊ฐœ๋…ํ•™์Šต์˜ ๋‚ด์šฉ์„ ์ˆœ์„œ๋Œ€๋กœ ๋ณด๋ฉด์„œ ํ•˜๋‚˜์”ฉ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • { 
        domain: 'localhost',
        path: '/',
        // domain๊ณผ path ์˜ต์…˜์€ ์ฟ ํ‚ค๋ฅผ ์ „๋‹ฌํ•  ๊ฒฝ๋กœ๋ฅผ ์ง€์ •ํ•ด์ค๋‹ˆ๋‹ค.
        // ์—‰๋šฑํ•œ ๊ณณ์œผ๋กœ๋„ ์ฟ ํ‚ค๋ฅผ ๋ณด๋‚ด๊ณ  ์‹ถ์ง€ ์•Š๋‹ค๋ฉด, ์ž˜ ์ž‘์„ฑํ•ด์ฃผ๋„๋ก ํ•ฉ์‹œ๋‹ค.
        
        // MaxAge, Expires ์˜ต์…˜์€ ๋กœ๊ทธ์ธ ์œ ์ง€ ์ฒดํฌ ์—ฌ๋ถ€์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์งˆํ…Œ๋‹ˆ ์ผ๋‹จ ํŒจ์Šคํ•ฉ๋‹ˆ๋‹ค.
        
        secure: true,
        // ์ง€๊ธˆ์€ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๋ชจ๋‘ localhost๋ผ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ์ƒ๊ด€ ์—†์ง€๋งŒ,
        // ๊ฐ€๋Šฅํ•˜๋ฉด secure ์˜ต์…˜์€ true๋กœ ์„ค์ •ํ•˜๋„๋ก ํ•ฉ์‹œ๋‹ค.
        // https๋ฅผ ํ†ตํ•ด ์ฟ ํ‚ค๋ฅผ ์ฃผ๊ณ ๋ฐ›์•„์•ผ ์ฟ ํ‚ค๊ฐ€ ์•”ํ˜ธํ™” ๋˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
        
        httpOnly: true,
        // httpOnly ์˜ต์…˜์€ ๋ฌด์กฐ๊ฑด true๋กœ ์„ค์ •ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
        // false์ผ ๊ฒฝ์šฐ ์ฟ ํ‚ค๊ฐ€ ํƒˆ์ทจ๋  ์œ„ํ—˜์ด ์ƒ๊ธฐ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.
        
        sameSite: 'strict',
        // ์„œ๋ฒ„๋Š” http://localhost:4000, ํด๋ผ์ด์–ธํŠธ๋Š” http://localhost:3000์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
        // ์ด ๋•Œ, ๋‘ ์ฃผ์†Œ๋Š” TLD(.com, .org ...)๋ฅผ ๊ฐ–๊ณ ์žˆ์ง€ ์•Š์•„ eTLD+1๋„ ์—†์ง€๋งŒ,
        // ๋™์ผํ•œ host(localhost)๋ฅผ ๊ฐ–๊ธฐ ๋•Œ๋ฌธ์— sameSite๋กœ ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค.
        // ๋‘ ์ฃผ์†Œ๊ฐ€ sameSite์ด๊ณ , ์ฟ ํ‚ค๋กœ ๋‹ด์•„์ค„ ์ •๋ณด๊ฐ€ ๋กœ๊ทธ์ธ ๊ด€๋ จ ์ •๋ณด์ธ ๋งŒํผ,
        // sameSite ๋‚ด์—์„œ๋งŒ ์ฟ ํ‚ค๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก strict๋กœ ์„ค์ •ํ•ด์ค์‹œ๋‹ค.
    } 
    • ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•œ ์ฟ ํ‚ค ์˜ต์…˜์„ cookiesOption์ด๋ผ๋Š” ์ด๋ฆ„์˜ ๊ฐ์ฒด๋กœ ๋งŒ๋“  ๋‹ค์Œ ์ „๋‹ฌ์ธ์ž๋กœ ๋„ฃ์–ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.
    • if (userInfo.id === undefined) {
      	... 
      } else {
      	res.cookie('cookieId', userInfo.id, cookiesOption)
      }
  • ์ฃผ์„์„ ๋ณด๋ฉด ์˜์†์„ฑ ์žˆ๋Š” ์ฟ ํ‚ค๋ฅผ ๋ณด๋‚ด๋ ค๋ฉด max-age ๋˜๋Š” expires ์˜ต์…˜์„ ์„ค์ •ํ•˜์„ธ์š”๋ผ๋Š” ์„ค๋ช…์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋กœ๊ทธ์ธ์„ ์œ ์ง€ํ•˜๊ณ  ์‹ถ์œผ๋ฉด ํ•ด๋‹น ์˜ต์…˜์„ ์ž‘์„ฑํ•˜๋ผ๋Š” ๋œป์ž…๋‹ˆ๋‹ค. ์ด ์˜ต์…˜์„ ์ž‘์„ฑํ•˜์ง€ ์•Š์œผ๋ฉด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๊บผ๋ฒ„๋ฆฌ๋ฉด ์ฟ ํ‚ค๊ฐ€ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

    • ๋กœ๊ทธ์ธ ์„ฑ๊ณต ๋กœ์ง์„ checkedKeepLogin์œผ๋กœ ํ•œ ๋ฒˆ ๋” ๋ถ„๊ธฐํ•˜๊ณ , true์ผ ๊ฒฝ์šฐ(๋กœ๊ทธ์ธ์„ ์œ ์ง€ํ•  ๊ฒฝ์šฐ)์— ํ•ด๋‹น ์˜ต์…˜์„ ์ถ”๊ฐ€๋กœ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”.

    • ...
      } else if (checkedKeepLogin === true) {
      	// ๋กœ๊ทธ์ธ์„ ์œ ์ง€ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ, cookiesOption์— max-age ๋˜๋Š” expires ์˜ต์…˜์„ ์ถ”๊ฐ€๋กœ ์„ค์ •ํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.
      
      	// max-age ์˜ต์…˜์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ
      	cookiesOption.maxAge = 1000 * 60 * 30
      	// ๋‹จ์œ„๋Š” ms(๋ฐ€๋ฆฌ์„ธ์ปจ๋“œ === 0.001์ดˆ)์ด๋‹ˆ ์ฃผ์˜ํ•˜์„ธ์š”! -> ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•  ๊ฒฝ์šฐ 30๋ถ„๋™์•ˆ ์ฟ ํ‚ค๋ฅผ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
      
      	// expires ์˜ต์…˜์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š”, ์ด๋ ‡๊ฒŒ ์ž‘์„ฑํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
      	cookiesOption.expires = new Date(Date.now() + (1000 * 60 * 30) )
      	// ์ง€๊ธˆ ์‹œ๊ฐ„ + 30๋ถ„ ํ›„์— ์ฟ ํ‚ค๋ฅผ ์‚ญ์ œํ•œ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค.
      
      	res.cookie('cookieId', userInfo.id, cookiesOption)
      } else {
      	// ๋กœ๊ทธ์ธ์„ ์œ ์ง€ํ•˜๊ณ  ์‹ถ์ง€ ์•Š์€ ๊ฒฝ์šฐ, max-age ๋˜๋Š” expires ์˜ต์…˜์„ ์ž‘์„ฑํ•˜์ง€ ์•Š์€ ์ƒํƒœ ๊ทธ๋Œ€๋กœ ์ฟ ํ‚ค๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
      	res.cookie('cookieId', userInfo.id, cookiesOption)
      }   
  • ์—ฌ๊ธฐ๊นŒ์ง€ ์ž‘์„ฑํ•˜๊ณ  ์ฃผ์„์„ ํ™•์ธํ•ด ๋ณด๋ฉด, ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ”๋กœ ์‘๋‹ต์„ ๋ณด๋‚ด์ง€ ์•Š๊ณ  ์„œ๋ฒ„์˜ /useinfo ์—”๋“œํฌ์ธํŠธ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ ์‹œ์ผœ์ฃผ๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

    • ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋Š” ์–ด๋–ป๊ฒŒ ํ•˜๋Š” ๊ฑด๊ฐ€์š”? redirect ๋ฉ”์„œ๋“œ์— ์—”๋“œํฌ์ธํŠธ๋ฅผ ์ „๋‹ฌํ•ด ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. โ†’ res.redirect("/userinfo")
      ์•„๊นŒ ๋กœ๊ทธ์ธํ•˜๋ฉด ์ฟ ํ‚ค๋ž‘ ํšŒ์› ์ •๋ณด๋ฅผ ๋ณด๋‚ด์ค˜์•ผ ํ•œ๋‹ค๊ณ  ํ–ˆ๋Š”๋ฐ, ์–ด๋–ป๊ฒŒ ๋œ ๊ฑธ๊นŒ์š”? โ†’ /login์—์„œ๋Š” ์ฟ ํ‚ค๋งŒ ๋ฐœ๊ธ‰ํ•˜๊ณ , /userinfo์—์„œ ํšŒ์› ์ •๋ณด๋ฅผ ๋ณด๋‚ด์ฃผ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค!

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

์ฒ˜์Œ์— ์•„์ด๋””๋ฅผ ์•„๋ฌด๊ฑฐ๋‚˜ ์น˜๊ณ  ๋กœ๊ทธ์ธ ์‹œ๋„๋ฅผ ํ–ˆ์—ˆ๋Š”๋ฐ, ์ •์ƒ์ ์œผ๋กœ userinfo๊ฐ€ ๋ณด์ด์ง€ ์•Š์•„์„œ ๋‹นํ™ฉํ–ˆ๋‹ค.

์•Œ๊ณ ๋ณด๋‹ˆ ํ˜„์žฌ๋กœ์„œ๋Š” ๋ชจ์˜ ๋ฐ์ดํ„ฐ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ, data.js ์•ˆ์— ์žˆ๋Š” ์ •ํ•ด์ง„ ๊ฐ’์„ ์ „ํ•ด์ค˜์•ผ ํ–ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์•„์ด๋””์™€ ๋น„๋ฒˆ์„ ์ž…๋ ฅํ•ด์ฃผ๋ฉด, ์ •์ƒ์ ์œผ๋กœ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ์‹œ,
ํ„ฐ๋ฏธ๋„์—์„œ userinfo๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ „๋‹ฌ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์–ธ๊ธ‰๋œ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ์— ๋Œ€ํ•ด์„œ๋Š” ์•„๋ž˜ Error note์—์„œ ๋‹ค๋ฃจ๊ฒ ๋‹ค.


โš™๏ธ /login.js


  • ์ฟ ํ‚ค๋ฅผ ๊ฒ€์ฆํ•ด์„œ ์œ ์ € ์ •๋ณด๋ฅผ ์ „๋‹ฌํ•ด ์ค์‹œ๋‹ค.

    • ์ผ๋‹จ ์ฟ ํ‚ค๋ฅผ ํ™•์ธํ•ด ๋ด…์‹œ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์— ์ฟ ํ‚ค๊ฐ€ ์žˆ๋‹ค๋ฉด ๋”ฐ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด์ฃผ์ง€ ์•Š์•„๋„ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ์„œ๋ฒ„๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
      • console.log(req.cookies)๋กœ ์ฟ ํ‚ค๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ์ฃผ์˜ : ๋กœ๊ทธ์ธ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ด๋ฃจ์–ด์ ธ์•ผ ์ฟ ํ‚ค๊ฐ€ ๋งŒ๋“ค์–ด์ง‘๋‹ˆ๋‹ค. data.js๋ฅผ ํ™•์ธํ•˜๊ณ  ์ž‘์„ฑ๋˜์–ด ์žˆ๋Š” ์ •๋ณด๋กœ ๋กœ๊ทธ์ธ์„ ์‹œ๋„ํ•ด ์ฃผ์„ธ์š”.
    • /login์—์„œ ์ฟ ํ‚ค๊ฐ€ ์ž˜ ๋งŒ๋“ค์–ด์กŒ๋‹ค๋ฉด, ์ฟ ํ‚ค๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ๋„ฃ์–ด์ค€ userinfo.id๊ฐ€ ๋“ค์–ด์žˆ๋Š” ๊ฑธ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ’์„ ์‚ฌ์šฉํ•ด์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ์ „๋‹ฌํ•ด ์ค„ ์œ ์ € ์ •๋ณด๋ฅผ ํ•„ํ„ฐ๋งํ•ฉ์‹œ๋‹ค.
  • login.js์— ์žˆ๋Š” ํ•„ํ„ฐ๋ง ๋กœ์ง์„ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ์™€์„œ ์žฌํ™œ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

  • const cookieId = req.cookies.cookieId
    const userInfo = {
        ...USER_DATA.filter((user) => user.id === cookieId)[0],
     };
    • ์ฃผ์˜ํ•  ์ 
      • user.userId๊ฐ€ ์•„๋‹ˆ๋ผ user.id๋กœ ํ•„ํ„ฐ๋งํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ—ท๊ฐˆ๋ฆฌ๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค!
      • ์œ ํšจํ•œ id๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ userInfo๊ฐ€ ๋น„์–ด์žˆ์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
      • ์ฟ ํ‚ค๊ฐ€ ์—†์„ ๋•Œ๋„ userInfo ๊ฐ’์ด ์ œ๋Œ€๋กœ ๋“ค์–ด์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
        • ๋”ฐ๋ผ์„œ ๋กœ๊ทธ์ธ ์‹คํŒจ ์กฐ๊ฑด๋ฌธ์€ if ( !cookieId || !userInfo.id )๋กœ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ์‘๋‹ต ์ฝ”๋“œ ์ž‘์„ฑํ•˜๊ธฐ

  • if (!cookieId || !userInfo.id){
        res.status(401).send('Not Authorized');
    } else {
    		// ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ผ์„œ ์‚ญ์ œ ํ›„์— ๋ณด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
        delete userInfo.password
        res.send(userInfo)
    }
  • ์ด์ œ ์„œ๋ฒ„์—์„œ ์‘๋‹ตํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์™„์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ์—์„œ ์ž˜ ๋“ค์–ด์˜ค๋Š”์ง€ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

    • ํด๋ผ์ด์–ธํŠธ์˜ Login.js ์—์„œ console.log(res.data)๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
    • return axios
      	.post(...)
      	.then((res) => {
      		// ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์•„์˜จ ๋‹ค์Œ ํ™•์ธํ•ด์•ผํ•˜๋ฏ€๋กœ ์ด ์œ„์น˜์—์„œ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
      		console.log(res.data)
      	})
      	...
    • ๊ทธ ํ›„ ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ๋ณด๋ƒˆ์„ ๋•Œ ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์ฐฝ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฐ’์ด ์ž˜ ๋“ค์–ด์˜จ๋‹ค๋ฉด ์‘๋‹ต์„ ์ •์ƒ์ ์œผ๋กœ ๋ฐ›๊ณ  ์žˆ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
      • ์‘๋‹ต๋ฐ›์€ ๊ฐ’์œผ๋กœ ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑ ์‹œ, ์ •์ƒ์ ์œผ๋กœ login ๋กœ์ง(์ฟ ํ‚ค ๋ฐœ๊ธ‰) ์ฒ˜๋ฆฌ ํ›„,
redirect๋กœ ์ธํ•ด userinfo ๊นŒ์ง€ ๋กœ์ง์ด ๊ตฌํ˜„๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๋˜ํ•œ ์ฝ˜์†”์ฐฝ์—์„œ ์ •์ƒ์ ์œผ๋กœ ์‘๋‹ต๋ฐ›๊ณ  ์žˆ๋Š” ๊ฐ’์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.


3. ํด๋ผ์ด์–ธํŠธ : ์‘๋‹ต์„ ๋ฐ›์•„ React ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธ

  • ์šฐ์„  ํด๋ผ์ด์–ธํŠธ์˜ App.js์—์„œ Login.js๋กœ ํ•„์š”ํ•œ props๋ฅผ ๋‚ด๋ ค์ฃผ์„ธ์š”. (setIsLogin, setUserInfo)

    • Login.js์—์„œ props๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ฝ”๋“œ๋„ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”.
  • ๋ฐ›์•„์˜จ ์ƒํƒœ ๋ณ€๊ฒฝ ํ•จ์ˆ˜๋กœ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ฉ๋‹ˆ๋‹ค.

    • setIsLogin(true) : ๋กœ๊ทธ์ธ๋˜์—ˆ์Œ์„ ์ƒํƒœ๋กœ ์ €์žฅํ•˜๊ธฐ
    • setUserInfo(res.data) : ๋กœ๊ทธ์ธํ•œ ํšŒ์›์˜ ์ •๋ณด๋ฅผ ์ƒํƒœ์— ์ €์žฅํ•˜๊ธฐ
  • catch๋ฅผ ํ†ตํ•ด ์—๋Ÿฌ ์ฒ˜๋ฆฌ๋„ ํ•ด์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค. ์—๋Ÿฌ๋Š” console.log(err.response.data)๋กœ ํ™•์ธํ•˜๊ณ , ์—๋Ÿฌ๋ฉ”์‹œ์ง€๋Š” setErrorMessage(โ€๋กœ๊ทธ์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค")๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

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

    • ๊ผญ ์•„๋ž˜์ฒ˜๋Ÿผ ์ดˆ๊ธฐํ™”ํ•  ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ํ•ด์ค„ ๋•Œ(์•„์ด๋””, ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ž…๋ ฅ๋˜์–ด ์žˆ๋Š”์ง€ ์—†๋Š”์ง€ ํ™•์ธํ•  ๋•Œ) ํ•ด์ฃผ๋Š” ๊ฒƒ๋„ ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

    • return axios
            .post("http://localhost:4000/login", {loginInfo, checkedKeepLogin})
            .then((res) => {
              setUserInfo(res.data)
              setIsLogin(true)
      
      				//์—ฌ๊ธฐ์—์„œ ์—๋Ÿฌ ์ดˆ๊ธฐํ™”
              setErrorMessage("")
            })
            .catch((err) => {
              console.log(err.response.data)
              setErrorMessage("๋กœ๊ทธ์ธ์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค.")
            });
          
    • ์—ฌ๊ธฐ๊นŒ์ง€ ์ž‘์„ฑํ–ˆ์œผ๋ฉด Login.js๋„ ์™„์„ฑ์ž…๋‹ˆ๋‹ค!


๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

์ด์ œ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ–ˆ์œผ๋ฏ€๋กœ, ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ํ™”๋ฉด์ด ๋„˜์–ด๊ฐ€๊ธฐ๋Š” ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์•„์ง Mypage.js ๊ตฌํ˜„์ด ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ๋‹น์—ฐํžˆ ์—๋Ÿฌ๊ฐ€ ๋œฌ๋‹ค.


4. ํด๋ผ์ด์–ธํŠธ : ํ™”๋ฉด ๋ฆฌ๋ Œ๋”๋ง โ†’ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์œผ๋กœ ๋งˆ์ดํŽ˜์ด์ง€ ํ‘œ์‹œ

  • App.js์—์„œ Mypage์— props๋กœ userInfo๋ฅผ ๋‚ด๋ ค์ฃผ์ง€ ์•Š์„ ๊ฒฝ์šฐ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. props๋ฅผ ์ œ๋Œ€๋กœ ๋‚ด๋ ค์ฃผ์„ธ์š”!

  • userInfo๋ฅผ ๋‚ด๋ ค์ค€ ํ›„ ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด Mypage๊ฐ€ ์ œ๋Œ€๋กœ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.


๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

์ด์ œ ์ •์ƒ์ ์œผ๋กœ ๋งˆ์ดํŽ˜์ด์ง€๊ฐ€ ํ™”๋ฉด์— ๋ณด์ธ๋‹ค !

์•„์ง ๊ตฌํ˜„์ด ํ•˜๋‚˜ ๋‚จ์•˜๋‹ค.


5. ํด๋ผ์ด์–ธํŠธ : ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ์„œ๋ฒ„์— ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ ๋ณด๋‚ด๊ธฐ

  • Mypage์— ์žˆ๋Š” ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด, ๋กœ๊ทธ์•„์›ƒ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์—”๋“œํฌ์ธํŠธ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ์ฃผ์„ธ์š”!
    • .post("http://localhost:4000/logout")

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

๋กœ๊ทธ์•„์›ƒ ์—”๋“œํฌ์ธํŠธ๋ฅผ ์„ค์ •ํ•ด์ค€ ๊ฒƒ์ฒ˜๋Ÿผ ํ„ฐ๋ฏธ๋„์„ ํ™•์ธํ•˜๋ฉด logout์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค !

ํ•˜์ง€๋งŒ ์ฝ”๋“œ ๊ตฌํ˜„์ด ์•„์ง ๋๋‚˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์˜ค๋ฅ˜๊ฐ€ ๋‚œ๋‹ค.


6. ์„œ๋ฒ„ : ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ ์ฒ˜๋ฆฌ

โš™๏ธ /logout.js

  • ์„œ๋ฒ„๋Š” ์ฟ ํ‚ค๋ฅผ ์‚ญ์ œํ•˜๊ณ , ์ƒํƒœ์ฝ”๋“œ๋กœ 205๋ฅผ ๋Œ๋ ค์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    • ์ฟ ํ‚ค๋ฅผ ์‚ญ์ œํ•  ๋• res.clearCookie ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
      • ์ธ์ž๋Š” ( ์ฟ ํ‚ค ์ด๋ฆ„, ์ฟ ํ‚ค ์˜ต์…˜ ) โ†’ ์ฟ ํ‚ค ์ด๋ฆ„์€ cookieId, ์˜ต์…˜์€ login.js์—์„œ ๋งŒ๋“ค์–ด์ค€ cookiesOption ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์™€์„œ ์“ฐ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    • const cookiesOption = {
          domain: 'localhost',
          path: '/',
         secure: true,
          httpOnly: true,
          sameSite: 'strict',
        }
      res.status(205).clearCookie('cookieId', cookiesOption).send("logout") 
         

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

์ด์ œ ์ •์ƒ์ ์œผ๋กœ ์ฟ ํ‚ค๊ฐ€ ์‚ญ์ œ๋˜์—ˆ๊ณ , ํ„ฐ๋ฏธ๋„์„ ํ™•์ธํ•ด๋ณด๋ฉด ์š”์ฒญ๋„ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.


7. ํด๋ผ์ด์–ธํŠธ๋Š” ์ƒํƒœ๋ฅผ ๋น„์šด๋‹ค.

  • Mypage์— props๋กœ ์ƒํƒœ๋ณ€๊ฒฝํ•จ์ˆ˜๋ฅผ ๋ฐ›์•„์™€์„œ ์ƒํƒœ๋ฅผ ๋น„์›Œ์ค๋‹ˆ๋‹ค.
    • setIsLogin(false) : ๋กœ๊ทธ์•„์›ƒ ๋˜์—ˆ์Œ์„ ์ƒํƒœ๋กœ ์ €์žฅํ•˜๊ธฐ
    • setUserInfo(null) : ์ €์žฅํ•ด ๋‘์—ˆ๋˜ ํšŒ์›์˜ ์ •๋ณด๋ฅผ ๋น„์šฐ๊ธฐ
  • ์—๋Ÿฌ๋„ ๋งˆ์ € ์ž‘์„ฑํ•ด ์ค๋‹ˆ๋‹ค.
    • console.log(err.response.data)

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

์ด์ œ ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅผ ์‹œ, ๋™์‹œ์— ์ •์ƒ์ ์œผ๋กœ ํ™ˆํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.


8. ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์œผ๋กœ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๊ฐ€ ํ‘œ์‹œ๋œ๋‹ค.

  • ์ด์ œ ๋กœ๊ทธ์•„์›ƒ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋‹ค์‹œ ์˜ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ, ๋กœ๊ทธ์ธ ์œ ์ง€ ์˜ต์…˜์„ ์„ ํƒํ•˜๊ณ  ๋กœ๊ทธ์ธํ•ด๋„, ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋„๊ณ  ๋‹ค์‹œ ์ ‘์†ํ–ˆ์„ ๋•Œ ๋กœ๊ทธ์ธ์ด ์œ ์ง€๊ฐ€ ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋กœ๊ทธ์ธ ์œ ์ง€ ๋กœ์ง์ด ์ž‘์„ฑ๋˜์–ด์žˆ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. App.js๋ฅผ ํ™•์ธํ•ด ๋ด…์‹œ๋‹ค.

    • useEffect๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ๋งˆ๋‹ค ์ตœ์ดˆ 1๋ฒˆ์”ฉ authHandler๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ๋•Œ๋ฌธ์— ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ ‘๊ทผํ–ˆ์„ ๋•Œ, ํด๋ผ์ด์–ธํŠธ์— ์ฟ ํ‚ค๊ฐ€ ์žˆ๋‹ค๋ฉด, ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์ฟ ํ‚ค๋„ ์ž๋™์œผ๋กœ ๋ณด๋‚ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
  • ์ฟ ํ‚ค๋ฅผ ํ™•์ธํ•˜๊ณ  ์ผ์น˜ํ•˜๋Š” ์œ ์ € ์ •๋ณด๋ฅผ ๋ณด๋‚ด์ฃผ๋Š” ์—”๋“œํฌ์ธํŠธ๋Š” ์–ด๋””์ธ๊ฐ€์š”? โ†’ /userinfo

    • ์ด ์—”๋“œํฌ์ธํŠธ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์•„์„œ ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    • ๊ทธ๋Ÿผ ์ฟ ํ‚ค๊ฐ€ ์œ ์ง€๋˜๋Š” ๋™์•ˆ์—๋Š” ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค
    • return axios
            .get("http://localhost:4000/userinfo")
            .then((res) => {
              setIsLogin(true)
              setUserInfo(res.data)
            })
            .catch((err) => {
              console.log(err.response.data)
            });
    • ์—ฌ๊ธฐ๊นŒ์ง€ ์ž‘์„ฑํ•˜์‹œ๋ฉด ์„œ๋ฒ„, ํด๋ผ์ด์–ธํŠธ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋„ ๋ชจ๋‘ ํ†ต๊ณผํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด



๐Ÿ’ก Error Note.


๐Ÿ’ก res.redirect

  • res.redirect๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ์ž๋ฅผ ๋‹ค๋ฅธ URL๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” Node.js์˜ Express ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์ด ํ•จ์ˆ˜๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ๋‹ค๋ฅธ URL๋กœ ๋ณด๋‚ด๊ณ , ํ•ด๋‹น URL์—์„œ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋ฅผ ๋กœ๋“œํ•˜๋„๋ก ์œ ๋„ํ•œ๋‹ค.

  • res.redirect ํ•จ์ˆ˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค:

    1. ๋ผ์šฐํŒ…: ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํŠน์ • ๊ฒฝ๋กœ๋กœ ์ ‘๊ทผํ–ˆ์„ ๋•Œ, ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜์—ฌ ํ•ด๋‹น ๊ฒฝ๋กœ์˜ ํ•ธ๋“ค๋Ÿฌ๋กœ ์š”์ฒญ์„ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ผ์šฐํŒ… ๋กœ์ง์„ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค.
    2. ์ธ์ฆ๊ณผ ๊ถŒํ•œ ๋ถ€์—ฌ: ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์— ์ ‘๊ทผํ•˜๋ ค๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ, ๋ฆฌ๋””๋ ‰์…˜์„ ํ†ตํ•ด ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ๋˜๋Š” ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์— ๋”ฐ๋ผ ํŠน์ • ํŽ˜์ด์ง€๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
    3. ์™ธ๋ถ€ ์‚ฌ์ดํŠธ๋กœ์˜ ๋ฆฌ๋””๋ ‰์…˜: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์™ธ๋ถ€ ์‚ฌ์ดํŠธ๋กœ ์‚ฌ์šฉ์ž๋ฅผ ๋ณด๋‚ผ ๋•Œ, res.redirect ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์†Œ์…œ ๋ฏธ๋””์–ด ์ธ์ฆ์„ ์œ„ํ•ด ์‚ฌ์šฉ์ž๋ฅผ OAuth ์ œ๊ณต์—…์ฒด๋กœ ๋ฆฌ๋””๋ ‰์…˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค.
  • res.redirect ํ•จ์ˆ˜์˜ ํ•„์š”์„ฑ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:

    1. ์‚ฌ์šฉ์ž ๊ฒฝํ—˜ ๊ฐœ์„ : ๋ฆฌ๋””๋ ‰์…˜์€ ์‚ฌ์šฉ์ž๊ฐ€ ์ƒˆ๋กœ์šด ํŽ˜์ด์ง€๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ ๊ฒฝ๋กœ๋กœ ์•ˆ๋‚ด๋˜์–ด ํšจ๊ณผ์ ์ธ ์›น ํƒ์ƒ‰์„ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ค€๋‹ค.
    2. ๋ณด์•ˆ๊ณผ ์ธ์ฆ: ๋ฆฌ๋””๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์ฆ๋˜์ง€ ์•Š์€ ์‚ฌ์šฉ์ž์˜ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๊ฑฐ๋‚˜, ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์•ก์„ธ์Šค ๊ถŒํ•œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
    3. SEO(Search Engine Optimization): URL ๋ฆฌ๋””๋ ‰์…˜์€ ๊ฒ€์ƒ‰ ์—”์ง„ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์ค‘์š”ํ•˜๋‹ค. ์˜ฌ๋ฐ”๋ฅธ ๋ฆฌ๋””๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์˜ค๋ž˜๋œ URL์„ ์ƒˆ๋กœ์šด URL๋กœ ๋ฆฌ๋””๋ ‰์…˜์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๊ฒ€์ƒ‰ ์—”์ง„์—์„œ ๋งํฌ ์ฃผ์†Œ๋ฅผ ๊ฐฑ์‹ ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋œ๋‹ค.
  • ์š”์•ฝํ•˜์ž๋ฉด, res.redirect ํ•จ์ˆ˜๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ์ž๋ฅผ ๋‹ค๋ฅธ URL๋กœ ๋ณด๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋ฉฐ, ์‚ฌ์šฉ์ž ๊ฒฝํ—˜, ๋ณด์•ˆ ๋ฐ ์ธ์ฆ, ๊ทธ๋ฆฌ๊ณ  SEO ๊ด€๋ จ ๋ชฉ์ ์„ ์œ„ํ•ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ’ก props๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜์ž !

  • // โœ… ์˜ฌ๋ฐ”๋ฅธ ์˜ˆ์‹œ
    export default function Mypage({ userInfo, setIsLogin, setUserInfo }) {
      const logoutHandler = () => {
        // TODO: Logout ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ์‹œ Login ํŽ˜์ด์ง€๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜์„ธ์š”.
        return axios
          .post("http://localhost:4000/logout")
          .then((res) => {
            setIsLogin(false);
            setUserInfo(null);
          })
          .catch((err) => {
            console.log(err.response.data);
          });
      };
  • // โŒ ํ‹€๋ฆฐ ์˜ˆ์‹œ
    export default function Mypage({ userInfo}) {
      const logoutHandler = ({setIsLogin, setUserInfo}) => {
        // TODO: Logout ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ์‹œ Login ํŽ˜์ด์ง€๋กœ ๋Œ์•„๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜์„ธ์š”.
        return axios
          .post("http://localhost:4000/logout")
          .then((res) => {
            setIsLogin(false);
            setUserInfo(null);
          })
          .catch((err) => {
            console.log(err.response.data);
          });
      };

  • ์•„๋ž˜์ฒ˜๋Ÿผ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด logoutHandler ํ•จ์ˆ˜๊ฐ€ ํด๋กœ์ €(Closure)์˜ ๊ฐœ๋…์„ ๋ฌด์‹œํ•ด๋ฒ„๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๊ฐ€ ๋‹น์—ฐํžˆ ์ œ๋Œ€๋กœ ๋Œ์•„๊ฐ€์ง€ ์•Š๋Š”๋‹ค. ๋”ฐ๋ผ์„œ ์œ„์™€ ๊ฐ™์ด ์ œ๋Œ€๋กœ ์ˆ˜์ •ํ•ด์ฃผ๋„๋ก ํ•˜์ž!


๐Ÿ’พ Session


์„ธ์…˜์œผ๋กœ ๋กœ๊ทธ์ธ ์œ ์ง€ ๊ตฌํ˜„ํ•˜๊ธฐ

  • ์ด๋ฒˆ ๊ณผ์ œ๋Š” ์ฟ ํ‚ค ํŠœํ† ๋ฆฌ์–ผ์—์„œ ์ง„ํ–‰ํ–ˆ๋˜ ํ๋ฆ„์—์„œ ์„œ๋ฒ„๊ฐ€ ์ฟ ํ‚ค ๋Œ€์‹  ์„ธ์…˜์„ ์ด์šฉํ•˜๋„๋ก ๋ฐ”๊ฟ”์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๋Š” ์ฟ ํ‚ค ํŠœํ† ๋ฆฌ์–ผ์˜ ์ฝ”๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๊ฐ€์ ธ๋‹ค ์‚ฌ์šฉํ•˜์„ธ์š”.

  • ์„ธ์…˜๋„ ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๊ธด ํ•˜์ง€๋งŒ, ์ฟ ํ‚ค๋กœ ๊ตฌํ˜„ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ์œ ์ € id๋ฅผ ์ง์ ‘ ๋‹ด๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ, ์„œ๋ฒ„์—์„œ ์„ธ์…˜ id๋ฅผ ๋ฐ›์•„์™€์„œ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

    • ์„œ๋ฒ„๋Š” ์„ธ์…˜ ์ €์žฅ์†Œ์— ์„ธ์…˜์„ ์ €์žฅํ•˜๊ณ , ์—ฌ๊ธฐ์— ํ•ด๋‹นํ•˜๋Š” ์„ธ์…˜ id๋ฅผ ์•”ํ˜ธํ™”ํ•ด์„œ ํด๋ผ์ด์–ธํŠธ์˜ ์ฟ ํ‚ค๋กœ ์ €์žฅํ•ด ๋‘ก๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์š”์ฒญ์ด ์˜ฌ ๋•Œ๋งˆ๋‹ค ์ฟ ํ‚ค์— ์žˆ๋Š” ์„ธ์…˜ id๋ฅผ ํ™•์ธํ•ด์„œ ์œ ์ €์ธ์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋•Œ ์„ธ์…˜ ์ €์žฅ, ์„ธ์…˜ id ์ƒ์„ฑ ๋“ฑ ์„ธ์…˜์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋กœ์ง์€ express-session์ด ๋งก์•„์„œ ์ฒ˜๋ฆฌํ•ด ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๋Š” express-session์˜ ์‚ฌ์šฉ๋ฒ•์— ๋งž์ถฐ์„œ ์‚ฌ์šฉํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
      index.js๋ฅผ ๋ณด๋ฉด express-session ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์ฟ ํ‚ค ์„ค์ •์ด ์ด๋ฏธ ๋˜์–ด์žˆ์œผ๋ฏ€๋กœ, ์ด๋ฒˆ์—๋Š” ์ฟ ํ‚ค ์„ค์ •์„ ๋”ฐ๋กœ ํ•ด์ฃผ์ง€ ์•Š์•„๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.
  • CORS ์„ค์ •์€ ์žŠ์ง€ ๋ง๊ณ  ํ•ด ์ฃผ์„ธ์š”! ์ฟ ํ‚ค ๋•Œ๋ž‘ ๋˜‘๊ฐ™์ด ํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • const corsOptions = {
      origin: "http://localhost:3000",
      credentials: true,
      methods: ['GET', 'POST', 'OPTION']
    };

โš™๏ธ /login


  • ์ฟ ํ‚ค ํŠœํ† ๋ฆฌ์–ผ ๋•Œ์™€ ๋กœ์ง์€ ๋˜‘๊ฐ™์Šต๋‹ˆ๋‹ค. ์„ธ์…˜์„ ์“ฐ๋ƒ ์ฟ ํ‚ค๋ฅผ ์“ฐ๋ƒ ์ฐจ์ด์ผ ๋ฟ์ด๋ผ, ์กฐ๊ฑด๋ฌธ ๋ถ„๊ธฐ๋Š” ๋˜‘๊ฐ™์ด ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ์— ์„ธ์…˜ id๋ฅผ ์ €์žฅํ•ด ๋ด…์‹œ๋‹ค.

    • req.session์„ ์‚ฌ์šฉํ•ด ์„ธ์…˜ ๊ฐ์ฒด์— userInfo.id๋ฅผ ์ €์žฅํ•˜์„ธ์š”.

    • // ์ด๋ฒˆ์—๋Š” ์ฟ ํ‚ค ํŠœํ† ๋ฆฌ์–ผ๊ณผ ๋‹ค๋ฅด๊ฒŒ res๊ฐ€ ์•„๋‹ˆ๋ผ req์— ์ž‘์„ฑํ•ด์•ผ๋ฉ๋‹ˆ๋‹ค. ์ •ํ•ด์ง„ ์‚ฌ์šฉ๋ฒ•์ด๋‹ˆ ์ฃผ์˜!!
      req.session.sessionId = userInfo.id
    • ์ด์ œ maxAge๋ฅผ ์„ค์ •ํ•ด์ฃผ๊ณ  ์‹ถ์€๋ฐ, ์„ธ์…˜์— ์ฟ ํ‚ค ์˜ต์…˜์„ ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•ด ์ค„ ์ˆ˜ ์žˆ์„๊นŒ์š”?

      • console.log(req.session)์œผ๋กœ ์„ธ์…˜์˜ ๊ตฌ์กฐ๋ฅผ ํ™•์ธํ•ด ๋ณด์„ธ์š”.

      • req.session.cookie ์•ˆ์— ๋„ฃ์–ด์ฃผ๋ฉด ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

      • ์˜ต์…˜์„ ๋„ฃ์–ด์ฃผ๊ณ  redirect๊นŒ์ง€ ์ž‘์„ฑํ•ด ์ค๋‹ˆ๋‹ค.

    • if (!userInfo.id) {
        res.status(401).send("Not Authorized")
      } else if (checkedKeepLogin) {
        req.session.sessionId = userInfo.id
      
        // ์„ธ์…˜ ๊ตฌ์กฐ ๋“ค์—ฌ๋‹ค๋ณด๊ธฐ -> ํ„ฐ๋ฏธ๋„์— ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค
        console.log(req.session)
      
        // ์ฟ ํ‚ค ์˜ต์…˜ ์„ค์ •ํ•˜๊ธฐ
        req.session.cookie.maxAge = 1000 * 60 * 30
      
        res.redirect('/userinfo')
      } else {
        req.session.sessionId = userInfo.id
        res.redirect('/userinfo')
      }

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

ํด๋ผ์ด์–ธํŠธ๋Š” ์ฟ ํ‚ค๋•Œ์™€ ๊ฐ™์œผ๋ฏ€๋กœ, ๊ตฌํ˜„์„ ์™„๋ฃŒํ•˜์˜€๋‹ค.

์„œ๋ฒ„ ์ชฝ์€ ์•„์ง ๊ตฌํ˜„์„ ํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋ˆŒ๋Ÿฌ๋„
๋ฐ˜์‘์ด ์—†์œผ๋ฉฐ, ํ„ฐ๋ฏธ๋„์ฐฝ์—์„œ ์‹ค์‹œ๊ฐ„ ๋ฉ”์„ธ์ง€ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.



โš™๏ธ /userinfo


  • ์šฐ๋ฆฌ๊ฐ€ sessionId๋กœ ์ €์žฅํ•ด ๋†“์€ ๊ฐ’์„ ์ด์šฉํ•ด์„œ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ณด๋‚ด์ค„ ์œ ์ € ์ •๋ณด๋ฅผ ์ฐพ์€ ๋‹ค์Œ ์‘๋‹ต์œผ๋กœ ๋ณด๋‚ด์ค์‹œ๋‹ค.
  • ๋กœ์ง์€ ๋˜‘๊ฐ™์œผ๋‹ˆ ์žฌํ™œ์šฉํ•˜๊ณ , cookieId๋ฅผ sessionId๋กœ ๋ฐ”๊ฟ”์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.
  • ํŒจ์Šค์›Œ๋“œ๋Š” ์ค‘์š”ํ•œ ์ •๋ณด์ด๋ฏ€๋กœ ์‘๋‹ต์„ ๋ณด๋‚ด๊ธฐ ์ „์— ์ง€์šฐ๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์„ธ์š”
  • const sessionId = req.session.sessionId
    const userInfo = {
      ...USER_DATA.filter((user) => user.id === sessionId)[0],
    };
    if (!sessionId || !userInfo.id){
      res.status(401).send('Not Authorized');
    } else {
      delete userInfo.password
      res.send(userInfo)
    }

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

userinfo ๋กœ์ง์„ ๊ตฌํ˜„ํ–ˆ์œผ๋ฏ€๋กœ, ๋กœ๊ทธ์ธ ๋ฒ„ํŠผ ๋ˆ„๋ฅด๋ฉด ๋กœ๊ทธ์ธ ๊ฐ€๋Šฅํ•˜๋‹ค.


โš™๏ธ /logout


  • ์ด์ œ ๋‚จ์€ ๊ฑด ๋กœ๊ทธ์•„์›ƒ๋ฟ์ž…๋‹ˆ๋‹ค.
  • ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด, ์„ธ์…˜์„ ์—†์• ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์„ธ์…˜ ์—†์• ์ฃผ๋Š” ๋ฉ”์„œ๋“œ๋กœ req.session.destroy๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
    • ์ƒํƒœ์ฝ”๋“œ๋กœ 205๋ฅผ ๋ณด๋‚ด์ฃผ๋Š” ๊ฒƒ ์žŠ์ง€ ๋งˆ์„ธ์š”.
    • req.session.destroy();
      res.status(205).send('Logged Out Successfully');
    • ์ด์ œ ์ƒˆ๋กœ๊ณ ์นจํ•ด๋„ ์„ธ์…˜์ด ๋‚จ์•„์žˆ๊ฒŒ ๋˜๊ณ , ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋„ ๋ชจ๋‘ ํ†ต๊ณผํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด



๐Ÿชช Token


ํ† ํฐ์ธ์ฆ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ


  • ํ† ํฐ์˜ ์ผ์ข…์ธ JSON Web Token์„ ์ด์šฉํ•˜์—ฌ ํ† ํฐ๋ฐฉ์‹ ์ธ์ฆ์„ ๊ตฌํ˜„ํ•œ๋‹ค.

  • ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋Š” ์ฟ ํ‚ค ๋ฐ ์„ธ์…˜ ์ธ์ฆ๋ฐฉ์‹๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.
    ๊ธฐ์กด ์ฟ ํ‚ค, ์„ธ์…˜ ๊ณผ์ œ์—์„œ ํ’€์—ˆ๋˜ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ์™€๋„ ๋ฉ๋‹ˆ๋‹ค.

  • ์ด๋ฒˆ ๊ณผ์ œ์—์„œ๋Š” JWT ์ƒ์„ฑ ๋ฐ ๊ฒ€์ฆ์„ ๋„์™€์ฃผ๋Š” ํ—ฌํผ ํŽ‘์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.
    helper/tokenFunctions.js์—์„œ ๊ฐ๊ฐ์˜ ๋ฉ”์„œ๋“œ๋“ค์˜ ์—ญํ• ์„ ๋จผ์ € ํŒŒ์•…ํ•˜์„ธ์š”.

  • ๋‹ค์Œ ์ˆœ์„œ๋กœ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ํŒŒ์ผ์—๋Š” ์ ์ ˆํ•œ ์œ„์น˜์— TODO:๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

  1. ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • server์˜ login controller ๊ตฌํ˜„
  2. ๋งˆ์ดํŽ˜์ด์ง€ ๊ตฌํ˜„
    • server์˜ userinfo controller ๊ตฌํ˜„
  3. ๋กœ๊ทธ์•„์›ƒ ๊ธฐ๋Šฅ ๊ตฌํ˜„
    • server์˜ logout controller ๊ตฌํ˜„
  • ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•˜๋”๋ผ๋„ ์œ ์ €์˜ ๋กœ๊ทธ์ธ ์ƒํƒœ๊ฐ€ ์œ ์ง€๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

1. controllers/login.js (POST /users/login)

  1. request๋กœ ๋ฐ›์€ userId, password์™€ ์ผ์น˜ํ•˜๋Š” ์œ ์ €๊ฐ€ DB์— ์กด์žฌํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  2. ์ผ์น˜ํ•˜๋Š” ์œ ์ €๊ฐ€ ์—†์„ ๊ฒฝ์šฐ:
    • ๋กœ๊ทธ์ธ ์š”์ฒญ์„ ๊ฑฐ์ ˆํ•ฉ๋‹ˆ๋‹ค.
  3. ์ผ์น˜ํ•˜๋Š” ์œ ์ €๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ:
    • ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์€ ๋‘ ์ข…๋ฅ˜์˜ JWT(access, refresh)๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  4. request๋กœ ๋ฐ›์€ checkedKeepLogin์„ ํ†ตํ•ด ๋กœ๊ทธ์ธ ์ƒํƒœ ์œ ์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
    • Access Token์€ ์„ธ์…˜ ์ฟ ํ‚ค, Refresh Token์€ ์˜์†์„ฑ ์ฟ ํ‚ค๋กœ ๋ณด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋กœ๊ทธ์ธ ์ƒํƒœ ์œ ์ง€๋ฅผ ์›ํ•œ๋‹ค๋ฉด Access Token์™€ Refresh Token ๋ชจ๋‘ ์ฟ ํ‚ค๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋กœ๊ทธ์ธ ์ƒํƒœ ์œ ์ง€๋ฅผ ์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด Access Token๋งŒ ์ฟ ํ‚ค๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  5. ํด๋ผ์ด์–ธํŠธ์— ๋ฐ”๋กœ ์‘๋‹ต์„ ๋ณด๋‚ด์ง€ ์•Š๊ณ  ์„œ๋ฒ„์˜ /userinfo๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

const { USER_DATA } = require("../../db/data");
const { generateToken } = require("../helper/tokenFunctions");

module.exports = async (req, res) => {
  const { userId, password } = req.body.loginInfo;
  const { checkedKeepLogin } = req.body;

  const userInfo = USER_DATA.filter(
    (user) => user.userId === userId && user.password === password
  );

  if (userInfo.length === 0) {
    res.status(401).send("Not Authorized");
  } else {
    const user = userInfo[0]; // ์ฒซ ๋ฒˆ์งธ ์ผ์น˜ํ•˜๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
    const accessToken = generateToken(user, "access");
    const refreshToken = generateToken(user, "refresh");

    if (checkedKeepLogin) {
      res.cookie("access_jwt", accessToken, { httpOnly: true });
      res.cookie("refresh_jwt", refreshToken, { httpOnly: true });
    } else {
      res.cookie("access_jwt", accessToken, { httpOnly: true });
    }

    res.redirect("/userinfo");
  }
};

2. controllers/userInfo.js (GET /users/userinfo)

  1. ์ฟ ํ‚ค์— Access Token์ด ์žˆ๋‹ค๋ฉด verifyToken ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด ์ด๋ฅผ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฒ€์ฆ๋˜์—ˆ๋‹ค๋ฉด ํ† ํฐ์— ๋‹ด๊ธด ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ์œ ์ € ์ •๋ณด๋ฅผ db์—์„œ ์กฐํšŒํ•œ ํ›„ ์‘๋‹ต์œผ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
  2. Access Token์ด ๊ฒ€์ฆ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด verifyToken ๋ฉ”์„œ๋“œ๋ฅผ ์ด์šฉํ•ด Refresh Token์„ ๊ฒ€์ฆํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฒ€์ฆ๋˜์—ˆ๋‹ค๋ฉด ํ† ํฐ์— ๋‹ด๊ธด ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ db์—์„œ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
      • Access Token์„ ๋‹ค์‹œ ๋ฐœ๊ธ‰ํ•ด ์ฟ ํ‚ค์— ๋‹ด๊ณ  ์œ ์ € ์ •๋ณด์™€ ํ•จ๊ป˜ ์‘๋‹ต์œผ๋กœ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฒ€์ฆ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์š”์ฒญ์„ ๊ฑฐ์ ˆํ•ฉ๋‹ˆ๋‹ค.
  3. Access Token, Refresh Token ๋ชจ๋‘ ์—†๋‹ค๋ฉด ์š”์ฒญ์„ ๊ฑฐ์ ˆํ•ฉ๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

const { USER_DATA } = require("../../db/data");
const { verifyToken, generateToken } = require("../helper/tokenFunctions");

module.exports = async (req, res) => {
  const accessToken = req.cookies.access_jwt;
  const refreshToken = req.cookies.refresh_jwt;

  if (!accessToken && refreshToken) {
    try {
      // Refresh Token ๊ฒ€์ฆ
      const decodedRefreshToken = verifyToken("refresh", refreshToken);
      const { id } = decodedRefreshToken;

      // Access Token ์žฌ๋ฐœ๊ธ‰
      const newAccessToken = generateToken({ id }, "access");

      res.cookie("access_jwt", newAccessToken, { httpOnly: true });

      // ์œ ์ € ์ •๋ณด ์กฐํšŒ
      const userInfo = USER_DATA.find((user) => user.id === id);

      if (userInfo) {
        res.status(200).json(userInfo);
      } else {
        res.status(401).send("Not Authorized");
      }
    } catch (refreshTokenError) {
      res.status(401).send("Not Authorized");
    }
  } else if (accessToken) {
    try {
      // Access Token ๊ฒ€์ฆ
      const decodedAccessToken = verifyToken("access", accessToken);
      const { id } = decodedAccessToken;

      // ์œ ์ € ์ •๋ณด ์กฐํšŒ
      const userInfo = USER_DATA.find((user) => user.id === id);

      if (userInfo) {
        res.status(200).json(userInfo);
      } else {
        res.status(401).send("Not Authorized");
      }
    } catch (accessTokenError) {
      if (accessTokenError.name === "TokenExpiredError") {
        res.status(401).send("Not Authorized");
      } else {
        res.status(500).send("Internal Server Error");
      }
    }
  } else {
    res.status(401).send("Not Authorized");
  }
};

3. controllers/logout.js (POST /users/logout)

  1. ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅ๋œ ์ฟ ํ‚ค์˜ ๊ฐ’(ํ† ํฐ)์„ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.
    • cookie-parser์˜ clearCookie ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ์ง์ ‘ ์ฟ ํ‚ค์˜ ๊ฐ’์„ ๋นˆ ๊ฐ’์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

module.exports = (req, res) => {
  res.clearCookie("access_jwt");
  res.clearCookie("refresh_jwt");

  res.status(205).send();
}


๐Ÿ’ผ OAuth


Oauth๋ฅผ ์ด์šฉํ•œ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ตฌํ˜„ํ•˜๊ธฐ


  • ์ด๋ฒˆ ๊ณผ์ œ์—์„œ๋Š” ์„œ๋ฒ„๊ฐ€ ์•„๋‹Œ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ € ์„œ๋ฒ„์—์„œ ๊ฐ ์ปจํŠธ๋กค๋Ÿฌ์˜ ์—ญํ• ์„ ํŒŒ์•…ํ•˜์„ธ์š”.

  • Login with Github ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ, Github์—์„œ ์ธ์ฆ์ด ์„ฑ๊ณตํ•˜๋ฉด Mypage์—์„œ ๋‚˜์˜ ์œ ์ € ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


1. GitHub์— ๋‚ด ์•ฑ ๋“ฑ๋ก

๋งํฌ ๋ฅผ ์ฐธ๊ณ ํ•˜์—ฌ, OAuth ์•ฑ์„ ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

Homepage URL ๋ฐ Authorization callback URL์€
ํ•ด๋‹น ๊ณผ์ œ์˜ํด๋ผ์ด์–ธํŠธ ์ฃผ์†Œ(http://localhost:3000)๋กœ ๋ฆฌ๋””๋ ‰์…˜ ํ•ฉ๋‹ˆ๋‹ค.

  • ์งˆ๋ฌธ: Authorization callback URL์€ ๋ฌด์—‡์ธ๊ฐ€์š”?
    • OAuth ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์ธ์ฆ ๊ณผ์ •์ด ๋๋‚œ ํ›„ ๋ฆฌ๋””๋ ‰์…˜์„ ํ†ตํ•ด ๋‹ค์‹œ ๋‚ด ์•ฑ์œผ๋กœ ์ด๋™ํ•˜๋Š” ์›๋ฆฌ์ด๋ฏ€๋กœ, ๋‚ด ์•ฑ์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ ์œ„ํ•œ Authorization callback URL์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

2. ํ™˜๊ฒฝ ์„ค์ •

GitHub App์—์„œ ์ œ๊ณตํ•˜๋Š” Client ID ๋ฐ Client Secret์˜ ์ •๋ณด๋ฅผ ์ฑ„์›Œ ๋„ฃ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  • ์ฃผ์˜: Client Secret์€ ํ•ญ์ƒ ๋น„๋ฐ€๋กœ ์ง€์ผœ์ ธ์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์„œ๋ฒ„์— .env.example ํŒŒ์ผ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์ผ๋ช…์„ .env๋กœ ์ˆ˜์ •ํ•˜์‹œ๊ณ ,
    ํŒŒ์ผ ์•ˆ์— CLIENT_ID์™€ CLIENT_SECRET ์ •๋ณด๋ฅผ ๋‹ด์•„์ฃผ์„ธ์š”.


์†Œ์…œ ๋กœ๊ทธ์ธ ๋กœ์ง ํ”Œ๋กœ์šฐ


ํ•ด๋‹น ๊ณผ์ œ์—์„œ OAuth App์„ ํ†ตํ•ด Access token์„ ๋ฐ›์•„์˜ค๋Š” ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

3. ํ™˜๊ฒฝ ์„ค์ •

  • ์ œ๊ณต๋˜๋Š” ์„œ๋ฒ„๋ฅผ ์‚ดํŽด๋ด…์‹œ๋‹ค. express๋ฅผ ์ด์šฉํ•ด ๋งŒ๋“  ๊ฐ„๋‹จํ•œ ์›น ์„œ๋ฒ„์ž…๋‹ˆ๋‹ค.
  • Access token์„ ๋ฐœ๊ธ‰๋ฐ›๋Š” ๊ณผ์ •์€ ์„œ๋ฒ„์—์„œ ์ด๋ฃจ์–ด์ง€๋Š” ๊ฒƒ์ด ๋”์šฑ ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๋ž˜์„œ ํด๋ผ์ด์–ธํŠธ์—์„œ ๋ฐ›์•„์˜จ Authorization code๋ฅผ ์„œ๋ฒ„์˜ /callback ์—”๋“œํฌ์ธํŠธ๋กœ ์ „๋‹ฌํ•ด ์„œ๋ฒ„์—์„œ Github Authorization ์„œ๋ฒ„์—๊ฒŒ Access token ๋ฐœ๊ธ‰์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค.

4. Authorization code ๋ฐ›์•„์˜ค๊ธฐ (Login Component)

  • ํด๋ผ์ด์–ธํŠธ ํŽ˜์ด์ง€๋Š” React๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ํด๋”์—์„œ npm start ๋ช…๋ น์–ด๋กœ ํด๋ผ์ด์–ธํŠธ๋ฅผ ์‹คํ–‰์‹œ์ผœ ๋ณด์„ธ์š”!
  • ์ง์ ‘ ๋ธŒ๋ผ์šฐ์ € ์ฐฝ์ด ์–ด๋–ป๊ฒŒ ๋ณ€ํ™”ํ•˜๋Š”์ง€ ๋ณด๊ณ  ์ฝ˜์†”์ฐฝ์— ๋œจ๋Š” ์—๋Ÿฌ ๋ฉ”์‹œ์ง€๋“ค์„ ํ™•์ธํ•˜๋ฉฐ ์†Œ์…œ ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝํ—˜์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ ํŽ˜์ด์ง€๋Š” App.js๋ฅผ ์‹œ์ž‘์œผ๋กœ ์ฃผ์„์— ์ ํ˜€ ์žˆ๋Š” ๊ฐ€์ด๋“œ๋ผ์ธ์„ ์ฐธ๊ณ ํ•ด ์ž‘์„ฑ์„ ์‹œ์ž‘ํ•˜์„ธ์š”.
  • ๊ฐ€์žฅ ๋จผ์ € ํ•ด์•ผ ํ•  ์ผ์€ Github App์— ์š”์ฒญ์„ ๋ณด๋‚ด Authorization code๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ผ์ž…๋‹ˆ๋‹ค.

5. Access token ๋ฐ›์•„ ์˜ค๊ธฐ (App Component)

  • Authorization code๋ฅผ ๋ฐ›์•„์™”๋‹ค๋ฉด App.js์˜ getAccessToken ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • ํ•ด๋‹น ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์— /callback ์—”๋“œํฌ์ธํŠธ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์œผ๋กœ ๋ฐ›์•„์˜จ Access token์€ App ์ปดํฌ๋„ŒํŠธ์˜ state์— ์ €์žฅํ•œ ํ›„, Mypage ์ปดํฌ๋„ŒํŠธ์—์„œ props๋กœ ๋‚ด๋ ค๋ฐ›์•„ ํ™œ์šฉํ•˜์„ธ์š”.

6. ๋กœ์ปฌ ์„œ๋ฒ„๋ฅผ ํ†ตํ•ด Github ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์— ์œ ์ € ์ •๋ณด ์š”์ฒญ (Mypage Component)

  • ๋ฐ›์•„์˜จ Access Token์œผ๋กœ Mypage ์ปดํฌ๋„ŒํŠธ์—์„œ ๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ API ์š”์ฒญ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์•ก์„ธ์Šค ํ† ํฐ์„ ์ด์šฉํ•ด /userinfo๋กœ ์š”์ฒญํ•˜๋ฉด ๋กœ์ปฌ ์„œ๋ฒ„์˜ ๋ฆฌ์†Œ์Šค์ธ serverResource์™€ Github Resource ์„œ๋ฒ„์— ์š”์ฒญํ•œ ๋ฆฌ์†Œ์Šค์ธ githubUserData๊ฐ€ ์‘๋‹ต์œผ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

  • ์™„์„ฑ๋œ ๋งˆ์ดํŽ˜์ด์ง€ ํ™”๋ฉด์—๋Š” ๋‚ด Github ์œ ์ € ์ •๋ณด์™€ ๋กœ์ปฌ ์„œ๋ฒ„์— ์žˆ๋Š” ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

7. ๋กœ๊ทธ์•„์›ƒ ๊ตฌํ˜„ํ•˜๊ธฐ (Mypage Component)

  • ๋กœ์ปฌ ์„œ๋ฒ„์˜ /logout์— ์•ก์„ธ์Šค ํ† ํฐ์„ ์ด์šฉํ•œ ์š”์ฒญ์„ ๋ณด๋‚ด ์œ ์ €์˜ ํ† ํฐ์„ ์ง€์›Œ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ์ด ์„ฑ๊ณตํ•˜๋ฉด ๊ทธ์— ๋”ฐ๋ฅธ ์ƒํƒœ ๋˜ํ•œ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


๊ตฌํ˜„ ์ฝ”๋“œ & ๊ฒฐ๊ณผ ํ™”๋ฉด

  • OAuth ์•ฑ์„ ๋“ฑ๋ก ๊ณผ์ •

// Client - Userinfo.js

import React from 'react';

export default function User({ githubUser, serverResource, logoutHandler }) {
  return (
    <>
      <img src={githubUser.avatar_url} alt='github_avatar' />
      <h3>๋‚ด ์ •๋ณด</h3>
      <div className='userinfo-field'>
        <div>
          {`๐Ÿ“– Studying at `} <b>{serverResource.bootcamp}</b>
        </div>
        <div>{`๐Ÿ“ Living in ${githubUser.location}`}</div>
        <div>{`๐Ÿ“ฌ Contact: ${githubUser.email}`}</div>
        <div>{`๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป ${serverResource.position}`}</div>
        <article>
          <h3>Bio</h3>
          <span>{githubUser.bio ? githubUser.bio : serverResource.bio}</span>
        </article>
      </div>
      <button id='logout-btn' onClick={logoutHandler}>
        LOGOUT
      </button>
    </>
  );
}


์ •๋ง ์‹ ๊ธฐํ•˜๊ฒŒ ํด๋ผ์ด์–ธํŠธ Userinfo ์ฝ”๋“œ์—์„œ ์„ค์ •ํ•œ ๊ฐ’
๊ทธ๋Œ€๋กœ ํ”„๋กœํ•„ ์‚ฌ์ง„์ด๋‚˜ ๋‚ด๋ถ€ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค..

๋งค์ผ ์ด์šฉ๋งŒ ํ•˜๋˜ OAuth๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋‹ˆ๊นŒ ์ •๋ง ์‹ ๊ธฐํ–ˆ๋‹ค.. ์‹ ์„ธ๊ณ„..

๋‹ค์Œ์€ 5, 6 ,7๋ฒˆ์„ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ๋ฅผ ์ฒจ๋ถ€ํ•˜๊ฒ ๋‹ค.

// Client - App.js

import "./App.css";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Login from "./pages/Login";
import Mypage from "./pages/Mypage";
import { useEffect, useState } from "react";
import axios from "axios";

function App() {
  const [isLogin, setIsLogin] = useState(false);
  const [accessToken, setAccessToken] = useState("");

  const getAccessToken = async (authorizationCode) => {
    // ๋ฐ›์•„์˜จ Authorization Code๋กœ ๋‹ค์‹œ OAuth App์— ์š”์ฒญํ•ด์„œ Access Token์„ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    // Access Token์€ ๋ณด์•ˆ ์œ ์ง€๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํด๋ผ์ด์–ธํŠธ์—์„œ ์ง์ ‘ OAuth App์— ์š”์ฒญ์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ณด์•ˆ์— ์ทจ์•ฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    // Authorization Code๋ฅผ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด์ฃผ๊ณ  ์„œ๋ฒ„์—์„œ Access Token ์š”์ฒญ์„ ํ•˜๋Š” ๊ฒƒ์ด ์ ์ ˆํ•ฉ๋‹ˆ๋‹ค.
    // TODO: ์„œ๋ฒ„์˜ /callback ์—”๋“œํฌ์ธํŠธ๋กœ Authorization Code๋ฅผ ๋ณด๋‚ด์ฃผ๊ณ  Access Token์„ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค.
    // Access Token์„ ๋ฐ›์•„์˜จ ํ›„ state์— Access Token์„ ์ €์žฅํ•˜์„ธ์š”
    axios
      .post("http://localhost:4000/callback", { authorizationCode })
      .then((res) => {
        setIsLogin(true);
        setAccessToken(res.data.accessToken);
        console.log(res.data);
      });
  };
  useEffect(() => {
    // Authorization Server๋กœ๋ถ€ํ„ฐ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ฆฌ๋””๋ ‰์…˜๋œ ๊ฒฝ์šฐ, Authorization Code๊ฐ€ ํ•จ๊ป˜ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.
    // ex) http://localhost:3000/mypage?code=5e52fb85d6a1ed46a51f
    const url = new URL(window.location.href);
    const authorizationCode = url.searchParams.get("code");
    if (authorizationCode) {
      getAccessToken(authorizationCode);
    }
  }, []);
  return (
    <BrowserRouter>
      <div className="main">
        <div className="container">
          <Routes>
            <Route
              path="/"
              element={
                isLogin ? (
                  <Mypage
                    /*TODO: ์ปดํฌ๋„ŒํŠธ์— ํ•„์š”ํ•œ props๋ฅผ ์ „๋‹ฌํ•˜์„ธ์š”. */
                    accessToken={accessToken}
                    setIsLogin={setIsLogin}
                  />
                ) : (
                  <Login />
                )
              }
            />
          </Routes>
        </div>
      </div>
    </BrowserRouter>
  );
}

export default App;

// Client - Login.js

import React from "react";
import githubLogo from "./../images/github.png";

export default function Login() {
  const CLIENT_ID = process.env.REACT_APP_CLIENT_ID;

  const loginRequestHandler = () => {
    // TODO: GitHub๋กœ๋ถ€ํ„ฐ ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์œ„ํ•ด GitHub๋กœ ์ด๋™ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ ์ ˆํ•œ URL์„ ์ž…๋ ฅํ•˜์„ธ์š”.
    // OAuth ์ธ์ฆ์ด ์™„๋ฃŒ๋˜๋ฉด authorization code์™€ ํ•จ๊ป˜ callback url๋กœ ๋ฆฌ๋””๋ ‰์…˜ ํ•ฉ๋‹ˆ๋‹ค.
    // ์ฐธ๊ณ : https://docs.github.com/en/free-pro-team@latest/developers/apps/identifying-and-authorizing-users-for-github-apps
    return window.location.assign(
      `https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}`
    );
  };

  return (
    <>
      <div className="left-box">
        <span>
          Education
          <p>for the</p>
          Real World
        </span>
      </div>
      <div className="right-box">
        <div className="right-box">
          <h1>AUTH STATES</h1>
          <h3>OAuth 2.0 ์†Œ์…œ ๋กœ๊ทธ์ธ</h3>
          <form onSubmit={(e) => e.preventDefault()}>
            <div className="input-field">
              <button type="submit" onClick={loginRequestHandler}>
                <img id="logo" alt="logo" src={githubLogo} />
                <span> LOGIN WITH GITHUB</span>
              </button>
            </div>
          </form>
        </div>
      </div>
    </>
  );
}

// Client - Mypage.js

import axios from "axios";
import React, { useEffect, useState } from "react";
import Loading from "./components/Loading";
import User from "./components/UserInfo";

export default function Mypage({ accessToken, setIsLogin }) {
  const [githubUser, setGithubUser] = useState(null);
  const [serverResource, setServerResource] = useState(null);
  const [isLoading, setIsLoading] = useState(true);

  const logoutHandler = () => {
    // TODO: /logout์„ ํ†ตํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์•„์›ƒ๋˜๋„๋ก ๊ตฌํ˜„ํ•˜์„ธ์š”.
    // prop์œผ๋กœ ๋ฐ›์€ Access Token์„ ์ด์šฉํ•ด /logout ์—”๋“œํฌ์ธํŠธ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด์•ผํ•ฉ๋‹ˆ๋‹ค.
    // ์š”์ฒญ์ด ์„ฑ๊ณตํ–ˆ๋‹ค๋ฉด isLogin ์ƒํƒœ๋ฅผ false๋กœ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
    axios
      .delete("http://localhost:4000/logout", {
        data: {
          accessToken,
        },
      })
      .then(() => setIsLogin(false))
      .catch((err) => console.log("๋‹ค์‹œ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค."));
  };

  useEffect(() => {
    // TODO: /userinfo๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋ฐ›์•„์˜ค์„ธ์š”.
    // prop์œผ๋กœ ๋ฐ›์€ Access Token์„ ์ด์šฉํ•ด /userinfo ์—”๋“œํฌ์ธํŠธ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด์•ผํ•ฉ๋‹ˆ๋‹ค.
    // ์‘๋‹ต์œผ๋กœ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ githubUser, serverResource์˜ ์ƒํƒœ๋กœ ์—…๋ฐ์ดํŠธํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.
    // isLoading ์ƒํƒœ๋ฅผ false๋กœ ์—…๋ฐ์ดํŠธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    if (!accessToken) {
      return; // accessToken์ด ์—†์œผ๋ฉด ์š”์ฒญ์„ ๋ณด๋‚ด์ง€ ์•Š์Œ
    }

    axios
      .post("http://localhost:4000/userinfo", { accessToken })
      .then((res) => {
        setGithubUser(res.data.githubUserData);
        setServerResource(res.data.serverResource);
        setIsLoading(false);
      })
      .catch((err) => console.log("๋‹ค์‹œ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค."));
  }, [accessToken]);

  return (
    <>
      <div className="left-box">
        {!isLoading && (
          <span>
            {`${githubUser.login}`}๋‹˜,
            <p>๋ฐ˜๊ฐ‘์Šต๋‹ˆ๋‹ค!</p>
          </span>
        )}
      </div>
      <div className="right-box">
        <div className="input-field">
          {isLoading ? (
            <Loading />
          ) : (
            <User
              githubUser={githubUser}
              serverResource={serverResource}
              logoutHandler={logoutHandler}
            />
          )}
        </div>
      </div>
    </>
  );
}


๐Ÿ’ก Error Note.


๐Ÿ’ก Delete, Payload, body ?

  • Client ํด๋”์—์„œ Mypage.js ํŒŒ์ผ์„ ๊ตฌํ˜„ํ•  ๋•Œ, 'delete ์š”์ฒญ์—์„œ accessToken ๊ฐ’์„ ์™œ .then์œผ๋กœ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ณ  ํŽ˜์ด๋กœ๋“œ๋กœ ์ฒ˜๋ฆฌํ• ๊นŒ' ์™€ 'accessToken ๊ฐ’์„ ์™œ data ์•ˆ์— ๋‹ด์•„์„œ ์ „๋‹ฌํ• ๊นŒ'ํ•˜๋Š” ์˜๋ฌธ์—์„œ ์‹œ์ž‘๋˜์—ˆ๋‹ค.

  • ํŽ˜์ด๋กœ๋“œ(Payload)์™€ .then() ๋ฉ”์„œ๋“œ๋Š” HTTP ์š”์ฒญ์„ ๋‹ค๋ฅธ ์ธก๋ฉด์—์„œ ๋‹ค๋ฃจ๋Š” ๊ฐœ๋…์ด๋‹ค.

  • ๊ฐ๊ฐ์˜ ์—ญํ• ๊ณผ ์ฐจ์ด์ , ์‚ฌ์šฉ๋ฒ•์„ ์‚ดํŽด๋ณด๊ฒ ๋‹ค.

  1. ํŽ˜์ด๋กœ๋“œ(Payload):
    • ํŽ˜์ด๋กœ๋“œ๋Š” HTTP ์š”์ฒญ์˜ ๋ณธ๋ฌธ(body)์— ํฌํ•จ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์˜๋ฏธํ•œ๋‹ค.
    • POST, PUT, PATCH์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค.
    • ์š”์ฒญ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋™์•ˆ ์„œ๋ฒ„๋กœ ์ „๋‹ฌํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•œ๋‹ค.
    • ์ฃผ๋กœ JSON, XML, ํผ ๋ฐ์ดํ„ฐ์™€ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ํ‘œํ˜„๋œ๋‹ค.
    • axios์—์„œ๋Š” ํŽ˜์ด๋กœ๋“œ๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด ์š”์ฒญ์˜ ์˜ต์…˜ ๊ฐ์ฒด์˜ data ์†์„ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค.
    • ์˜ˆ์‹œ: axios.post(url, data)

  2. .then() ๋ฉ”์„œ๋“œ:
    • .then() ๋ฉ”์„œ๋“œ๋Š” Promise ๊ฐ์ฒด์˜ ๋ฉ”์„œ๋“œ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.
    • ๋น„๋™๊ธฐ ์š”์ฒญ(์˜ˆ: HTTP ์š”์ฒญ)์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋œ ํ›„์— ์‹คํ–‰๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•œ๋‹ค.
    • ์ฆ‰, ์‘๋‹ต์ด ๋„์ฐฉํ•˜๊ณ  ์„ฑ๊ณต ์ƒํƒœ ์ฝ”๋“œ๊ฐ€ ๋ฐ˜ํ™˜๋œ ๊ฒฝ์šฐ์— ์‹คํ–‰๋œ๋‹ค.
    • .then() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ฑฐ๋‚˜ ํŠน์ • ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.
    • axios์—์„œ๋Š” .then() ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋น„๋™๊ธฐ ์š”์ฒญ์˜ ์„ฑ๊ณต ์ฝœ๋ฐฑ์„ ์ •์˜ํ•œ๋‹ค.
    • ์˜ˆ์‹œ: axios.get(url).then(response => { // ์„ฑ๊ณต ์ฒ˜๋ฆฌ })

์š”์•ฝํ•˜๋ฉด ํŽ˜์ด๋กœ๋“œ๋Š” ์š”์ฒญ ๋ณธ๋ฌธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ „์†กํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋˜๊ณ ,
.then() ๋ฉ”์„œ๋“œ๋Š” ๋น„๋™๊ธฐ ์š”์ฒญ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋œ ํ›„์— ์‹คํ–‰๋˜๋Š” ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•œ๋‹ค.

๋”ฐ๋ผ์„œ accessToken์€ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋„˜๊ฒจ์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— payload(์œ„์น˜)์— ์žˆ๋Š” ๊ฒƒ์ด ๋งž๋‹ค.


๊ทธ๋ฆฌ๊ณ  ์ด ๋งํฌ์— ๋”ฐ๋ฅด๋ฉด HTTP DELETE ๋ฉ”์„œ๋“œ์—๋Š” ์š”์ฒญ ๋ณธ๋ฌธ์ด ์—†์–ด์•ผ ํ•œ๋‹ค.

HTTP ํ”„๋กœํ† ์ฝœ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ DELETE ์š”์ฒญ์—์„œ ๋ณธ๋ฌธ(payload)์„ ์ „์†กํ•˜๊ธฐ ์œ„ํ•œ ๋ช…์‹œ์ ์ธ ๊ทœ์•ฝ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๋Š”๋‹ค.

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

data ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:

  • Axios๊ฐ€ DELETE ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ, ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณธ๋ฌธ์ด ๋น„์–ด์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ช‡๋ช‡ API ์„œ๋ฒ„๋Š” DELETE ์š”์ฒญ์˜ ๋ณธ๋ฌธ์„ ์‚ฌ์šฉํ•˜๊ธฐ๋ฅผ ์›ํ•  ์ˆ˜ ์žˆ๋‹ค. data ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด Axios๊ฐ€ DELETE ์š”์ฒญ์— ๋ณธ๋ฌธ์„ ํฌํ•จ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

  • โœจ DELETE ์š”์ฒญ์˜ ๋ณธ๋ฌธ์€ ์„œ๋ฒ„์—์„œ ํŠน์ • ๋ฐ์ดํ„ฐ๋ฅผ ๊ธฐ๋Œ€ํ•˜๊ฑฐ๋‚˜ ์ฒ˜๋ฆฌํ•  ๋•Œ ์œ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์•ก์„ธ์Šค ํ† ํฐ์„ DELETE ์š”์ฒญ์˜ ๋ณธ๋ฌธ์— ํฌํ•จํ•˜์—ฌ ๋กœ๊ทธ์•„์›ƒ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒฝ์šฐ, ์„œ๋ฒ„๋Š” ์•ก์„ธ์Šค ํ† ํฐ์„ ํ™•์ธํ•˜๊ณ  ํ•ด๋‹น ์‚ฌ์šฉ์ž๋ฅผ ๋กœ๊ทธ์•„์›ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ผ๋ถ€ ์„œ๋ฒ„ ๊ตฌํ˜„์€ DELETE ์š”์ฒญ์˜ ๋ณธ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋‹ค ํŽธ๋ฆฌํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ, data ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ DELETE ์š”์ฒญ์˜ ๋ณธ๋ฌธ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ DELETE ์š”์ฒญ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณธ๋ฌธ์— ํฌํ•จํ•˜๋Š” ๊ฒƒ์€
์ผ๋ฐ˜์ ์ธ ํŒจํ„ด์€ ์•„๋‹ˆ๋ฉฐ, ๋ชจ๋“  ์„œ๋ฒ„๊ฐ€ ์ด๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.

API ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ์„œ๋ฒ„ ๊ฐœ๋ฐœ์ž์™€ ํ˜‘์˜ํ•˜์—ฌ ์˜ฌ๋ฐ”๋ฅธ ์š”์ฒญ ๋ฐฉ์‹์„ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.

axios
      .post("http://localhost:4000/userinfo", { accessToken })
      .then((res) => {
        setGithubUser(res.data.githubUserData);
        setServerResource(res.data.serverResource);
        setIsLoading(false);
      })
      .catch((err) => console.log("๋‹ค์‹œ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค."));
  }, [accessToken]);
axios
      .delete("http://localhost:4000/logout", {
        data: {
          accessToken,
        },
      })
      .then(() => setIsLogin(false))
      .catch((err) => console.log("๋‹ค์‹œ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค."));


์˜ค๋Š˜ ๊ตฌํ˜„ํ•œ ์˜ˆ์‹œ ์ฝ”๋“œ๋ฅผ ๋ด๋„ post๋Š” ๊ทธ๋ƒฅ ์ „๋‹ฌํ•˜๋‚˜, delete๋Š” data์— ๋‹ด์•„์„œ ์ „๋‹ฌํ•œ๋‹ค.

๋”ฐ๋ผ์„œ delete ๋ฉ”์„œ๋“œ๋Š” payload body ๊ฐ€ ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์—,
Delete ๋ฉ”์„œ๋“œ๋กœ payload body๋ฅผ ์‹ค์–ด ์š”์ฒญ์„ ํ•˜๋ฉด ์š”์ฒญ์ด ๊ฑฐ์ ˆ๋  ์ˆ˜ ์žˆ๋‹ค.

์ „๋‹ฌ์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์ด๋ผ๋ฉด, data ์†์„ฑ์— ๋‹ด์•„์„œ ์š”์ฒญํ•ด์•ผ ํ•œ๋‹ค.

profile
์•„์ด๋””์–ด๊ฐ€ ๋„˜์น˜๋Š” ํ”„๋ก ํŠธ์—”๋“œ๋ฅผ ๊ฟˆ๊ฟ‰๋‹ˆ๋‹ค ๐Ÿ”ฅ

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