[TIL] 211201

dev·2021년 12ė›” 1ėž
0

TIL

ëŠĐ록 ëģīęļ°
105/204
post-thumbnail

📝 ė˜Ī늘 한 ęēƒ

  1. res.locals / MongoStore / saveUninitialized / 도ëДėļ / expires / .env

📚 ë°°ėšī ęēƒ

user authentication

1. 로ę·ļėļ

ė–ī렜 ęģĩëķ€ė—ė„œ ėīė–īė„œ

export const postLogin = (req, res) => {
  // ėƒëžĩ
  
  // user뗐 대한 ė •ëģīëĨž ė„ļė…˜ė— ėķ”ę°€í•œë‹Ī
  req.session.loggedIn = true;
  req.session.user = user;
  return res.redirect("/");
};

ėī렜 req.session뗐 ėķ”ę°€í•œ loggedInęģž user ę°’ė€ ëŠĻ든 ėŧĻíŠļëĄĪëŸŽė—ė„œ ė‚ŽėšĐ 가ëŠĨ하ë‹Ī.

1) 프론íŠļė—”ë“œė— í‘œė‹œ (템플ëĶŋ ėˆ˜ė •)

ë‹ĪėŒėœžëĄœ user뗐ęēŒ ëĄœę·ļėļ뗐 ė„ąęģĩí–ˆėŒė„ ė•ŒëĶŽęļ° ėœ„í•ī ė„ļė…˜ė— ęļ°ë°˜í•ī 프론íŠļė—”ë“œė— ë‚īėšĐėī í‘œė‹œë˜ë„ëĄ 템플ëĶŋė„ ėˆ˜ė •í•īė•ž 한ë‹Ī.
req.session.loggedInėī falseėž 때 base.pug íŒŒėžė—ė„œ Joinęģž Login 링큎ëĨž ëģīė—ŽėĢžęģ , trueėž 때 Logoutęģž profile 링큎ëĨž ëģīė—ŽėĢžë„ëĄ í•īė•ž 한ë‹Ī.

ėīëĨž ėœ„í•īė„  템플ëĶŋė—ė„œ req.session.loggedIn ę°’ė„ ė‚ŽėšĐ할 눘 ėžˆė–īė•ž 한ë‹Ī.
pug뙀 express는 res.renderëĨž ėīėšĐí•˜ė§€ ė•Šęģ ë„ express middlewareëĨž 만ë“Īė–ī res.localsëĨž ėīėšĐí•ī 템플ëĶŋ뗐 ëģ€ėˆ˜ëĨž ė „ė—­ė ėœžëĄœ ëģī낾 눘 ėžˆë‹Ī.
ėī ė ė„ ėīėšĐí•ī locals object뗐 로ę·ļėļ한 userëĨž ėķ”ę°€í•œ 후 ėīëĨž 템플ëĶŋ뗐 가ė ļ뙀 프론íŠļė—”ë“œė— í‘œė‹œí•  눘 ėžˆë‹Ī.

ëĻžė €, src íīë”ė— middlewares.js íŒŒėžė„ 만든 후 localsMiddlewareëĨž 만ë“Īė–ī export 한ë‹Ī.
server.js íīë”ė—ė„œ localsMiddleware가 session middleware ë’Ī뗐 ė˜Ī도록 ėž‘ė„ąí•œë‹Ī.
ę·ļëž˜ė•žë§Œ localsMiddlewareė—ė„œ 로ę·ļėļ한 user뗐 대한 ė •ëģī가 ėžˆëŠ” session뗐 ė ‘ę·ží•  눘 ėžˆęļ° ë•ŒëŽļėīë‹Ī.

// middlewares.js
export const localsMiddleware = (req, res, next) => {
  res.locals.siteName = "Wetube";
  res.locals.loggedIn = Boolean(req.session.loggedIn);
  res.locals.loggedInUser = req.ssesion.user;
  next();
};
// server.js
import session from "express-session";
import { localsMiddleware } from "./middlewares";

app.use(session({
  secret: "Hello!",
  resave: true,
  saveUninitialized: true,
}));

app.use(localsMiddleware);

res.localsė˜ loggedIn ę°’ė„ ęļ°ë°˜ėœžëĄœ base.pug íŒŒėžė˜ navëĨž ėˆ˜ė •í•œë‹Ī.

user가 로ę·ļėļ ėƒíƒœę°€ ė•„ë‹ˆëžëĐī loggedInUser(ė͉, req.session.user)는 undefined ę°’ė„ ę°€ė§ˆ ęēƒėīë‹Ī.
ë”°ëžė„œ 프로필 ëДë‰ī는 user가 로ę·ļėļ ėƒíƒœėž ęē―ėš°ė—ë§Œ ëģīėī도록 한ë‹Ī.

nav
  ul
    if loggedIn
      li
        a(href="/logout") Log out
      li
        a(href="/my-profile") #{loggedInUser.name}ė˜ Profile
    else
      li
        a(href="/join") Join
        a(href="/login") Login

ėī렜 로ę·ļėļ/로ę·ļ ė•„ė›ƒ ėƒíƒœė— 따띾 ëДë‰ī가 ë‹Žëžė§€ëŠ” ęēƒė„ 확ėļ할 눘 ėžˆë‹Ī.

ðŸ’Ą postLogin ėŧĻíŠļëĄĪ럮

📌 ė•„ėī디 ë§žëŠ”ė§€ 확ėļ
📌 ëđ„ë°€ëēˆí˜ļ ë§žëŠ”ė§€ 확ėļ
📌 req.sessionė„ ėīėšĐí•ī ė„ļė…˜ė— user ė •ëģī ėķ”ę°€
📌 res.localsëĨž ėīėšĐí•ī 프론íŠļė—”ë“œė— 로ę·ļėļ ė—Žëķ€ė— 따띾 닮ëĶŽ í‘œė‹œ (ëŊļë“Īė›Ļė–ī)

2) MongoStore

session id는 ėŋ í‚Ī뗐 ė €ėžĨë˜ė§€ë§Œ, session 데ėī터는 ė„œëē„뗐 ė €ėžĨ된ë‹Ī.
ė„œëē„뗐 ėžˆëŠ” session storage는 ęļ°ëģļė ėœžëĄœ memory storeėīë‹Ī.
ë”°ëžė„œ, ė„œëē„ëĨž ėžŽė‹œėž‘í•˜ëĐī session 데ėī터는 ė‚Žëžė§„ë‹Ī.
ė„œëē„ę°€ ėžŽė‹œėž‘í•ī도 sessionėī ė‚Žëžė§€ė§€ ė•Šë„ëĄ 하ë ĪëĐī sessionė„ mongoDB뙀 ė—°ęē°í•īė•ž 한ë‹Ī.

(1) connect-mongo ė„Īėđ˜

express - connect-mongo ė°ļęģ 

$ npm install connect-mongo

connect-mongoëĨž ė„Īėđ˜í•œ 후 server.js íŒŒėžė—ė„œ mongoStoreëĨž import 하ęģ  MongoDB뗐 sessionsëĨž 만든ë‹Ī.

import mongoStore from "connect-mongo"; // ėķ”ę°€ ❗

app.use(session({
  secret: "Hello!",
  resave: true,
  saveUninitialized: true,
  store: MongoStore.create({ mongoUrl: "mongodb://127.0.0.1:27017/wetube" }), // ėķ”ę°€ ❗
}));

MongoDB shellė—ė„œ collectionsëĨž ęē€ėƒ‰í•˜ëĐī sessions가 만ë“Īė–īė§„ ęēƒė„ 확ėļ할 눘 ėžˆë‹Ī.

> show collections
sessions
users
videos

(2) session 만ë“Īęļ°

ė•„ė§ė€ sessions뗐 ė•„ëŽī런 session도 ėĄīėžŽí•˜ė§€ ė•ŠëŠ”ë‹Ī.
sessionė„ 만ë“Īęļ° ėœ„í•ī ė›đ ė‚ŽėīíŠļëĨž ėƒˆëĄœęģ ėđĻ í•œë‹Ī.
로ę·ļėļė„ 하ëĐī Log outęģž í”„ëĄœí•„ ëДë‰ī가 뜮ë‹Ī.
MongoDB shellė—ė„œ sessionėī 만ë“Īė–īė§„ ęēƒė„ 확ėļ할 눘 ėžˆë‹Ī.

> db.sessions.find()
{ "_id" : "pc__EnaXP5gY37scJHXEEy8SktMy17oL", "expires" : ISODate("2021-12-15T06:49:53.129Z"), "session" : "{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"loggedIn\":true,\"user\":{\"_id\":\"61a6b4041bee12373c5042ff\",\"email\":\"syong@naver.com\",\"username\":\"syong\",\"password\":\"$2b$05$zShlHon.zCXKrsSbJGzOfeuIm9vDFHasBIDiq6PsKPFSE0WV4n9WG\",\"name\":\"leesyong\",\"location\":\"goyang\",\"__v\":0}}" }

ėīė œëŠ” ė„œëē„ëĨž ë‹Ŧė€ 후 ėžŽė‹œėž‘í•ī도 ė—Žė „ížˆ 로ę·ļėļ ėƒíƒœėļ ęąļ 확ėļ할 눘 ėžˆë‹Ī. (âˆĩ ė›đ ė‚ŽėīíŠļ ëДë‰ī뙀 mongodb sessions ę·ļ대로)
sessionėī ė„œëē„ę°€ ė•„ë‹ˆëž 데ėī터ëē ėīėŠĪ뗐 ė €ėžĨ되ė–ī ėžˆęļ° ë•ŒëŽļėīë‹Ī.

3) 로ę·ļėļ한 user만 데ėī터ëē ėīėŠĪ뗐 ė €ėžĨ하ęļ°

í˜„ėžŽ session ė―”ë“œ

app.use(session({
  secret: "Hello!",
  resave: true,
  saveUninitialized: true,
  store: MongoStore.create({ mongoUrl: "mongodb://127.0.0.1:27017/wetube" }),
}));

ė„œëē„는 ë°ĐëŽļ하는 'ëŠĻ든 user'뗐ęēŒ session idëĨž ėĢžęģ , í•īë‹đ user뗐 대한 ė •ëģīëĨž 폎í•Ļ하는 ę·ļ sessionė€ 데ėī터ëē ėīėŠĪ뗐 ė €ėžĨ된ë‹Ī.
ę·ļ런데 ëī‡ėī나 로ę·ļėļ í•˜ė§€ ė•Šęģ  ęĩŽęē―만 하는 userë“Īėī ë°ĐëŽļ한 ęē―ėš°ė—ë„ ę·ļë“Ī뗐 대한 ė •ëģīëĨž 폎í•Ļ하는 sessionėī 데ėī터ëē ėīėŠĪ뗐 ė €ėžĨ된ë‹Ī.
ėĩëŠ…ė˜ useręđŒė§€ ė €ėžĨ하는 ęēƒė€ 너ëŽī ëđ„íšĻėœĻ렁ėīëŊ€ëĄœ ėīëĨž ėˆ˜ė •í•īė•ž 한ë‹Ī.

req.session.loggedIn = true;
req.session.user = user;

sessionėī ėƒˆëĄœ 만ë“Īė–īė§„ 후 ėˆ˜ė •ëœ 렁ėī ė—†ėœžëĐī, unininitialized ėƒíƒœëžęģ  í•œë‹Ī.
sessionė„ ėˆ˜ė •í•˜ëŠ” ęēƒė€ ė˜Ī링 ėŧĻíŠļëĄĪëŸŽė—ė„œ 가ëŠĨ한데, postLogin ėŧĻíŠļëĄĪëŸŽė—ė„œ sessionė„ ėˆ˜ė •í•˜ëŠ” ė―”ë“œëŠ” ėœ„ė™€ 같ë‹Ī.

app.use(session({
  secret: "Hello!",
  resave: false, // ėˆ˜ė • ❗
  saveUninitialized: false, // ėˆ˜ė • ❗
  store: MongoStore.create({ mongoUrl: "mongodb://127.0.0.1:27017/wetube" }),
}));

'ë˜‘ę°™ė€ sessionė€ 한 ëēˆë§Œ ė €ėžĨ'하ęļ° ėœ„í•īė„œëŠ”, resave ė†ė„ąė˜ ę°’ė„ trueė—ė„œ false로 ėˆ˜ė •í•īė•ž 한ë‹Ī. (true띞ëĐī 'user'가 로ę·ļėļ할 때마ë‹Ī sessionė„ 데ėī터ëē ėīėŠĪ뗐 ė €ėžĨ한ë‹Ī.)

'user가 로ę·ļėļí–ˆė„ 때만' sessionė„ 데ėī터ëē ėīėŠĪ뗐 ė €ėžĨ하ęļ° ėœ„í•īė„œëŠ”, server.js íŒŒėžė˜ session ëķ€ëķ„ė—ė„œ saveuninitialized ė†ė„ąė˜ ę°’ė„ trueė—ė„œ false로 ėˆ˜ė •í•īė•ž 한ë‹Ī.
ėī는 ėīˆęļ°í™”ë˜ė§€ ė•Šė€ sessionė€ store뗐 ė €ėžĨí•˜ė§€ ė•ŠėŒė„ ė˜ëŊļ한ë‹Ī.
sessionėī ėˆ˜ė •ë˜ė—ˆė„ 때만(ė͉, user가 로ę·ļėļ í–ˆė„ 때만) ė„œëē„는 ëļŒëžėš°ė €ė— ė„ļė…˜ idëĨž 넘ęēĻėĢžęģ , í•īë‹đ user뗐 대한 ė •ëģī가 ë‹īęļī sessionė„ 데ėī터ëē ėīėŠĪ뗐 ė €ėžĨ하도록 하는 ęēƒėīë‹Ī.
ėī렜 로ę·ļėļí•˜ė§€ ė•Šė€ user뗐 대한 ė •ëģī는 데ėī터ëē ėīėŠĪ뗐 ė €ėžĨë˜ė§€ ė•ŠëŠ”ë‹Ī.

4) ėŋ í‚Ī(cookie)

(1) 도ëДėļ(domain)

ėŋ í‚ĪëĨž 만든 ė„œëē„(ėŋ í‚ĪëĨž ė „ė†Ąí•īė•ž 하는 ė„œëē„)ëĨž 말한ë‹Ī.

(2) expires

만ë̌ ë‚ ė§œëĨž 맀렕í•īėĢžė§€ ė•ŠėœžëĐī session cookie가 된ë‹Ī.
session cookie는 user가 ëļŒëžėš°ė €ëĨž ë‹ŦėœžëĐī ė‚Žëžė§„ë‹Ī.

Max-Age란 cookie가 만ëĢŒë˜ëŠ” ë‚ ė§œëĨž 말한ë‹Ī.
1/1000ėīˆ ë‹Ļėœ„ëĄœ ėž‘ė„ąí•  눘 ėžˆë‹Ī.

똈ëĨž ë“Īė–ī ė•„ëž˜ė™€ 같ėī ėž‘ė„ąí•˜ëĐī 로ę·ļėļ한 í›„ė— 10ėīˆę°€ ė§€ë‚˜ëĐī ėŋ í‚Ī는 ė‚Žëžė§€ęģ  ėžë™ėœžëĄœ 로ę·ļė•„ė›ƒëœë‹Ī.

app.use(session({
  cookie: {
    maxAge: 10000,
  },
}));

ėī는 ė˜ˆė‹œėž ëŋ, ė‹Īė œëĄœ í˜„ėžŽ í”„ëĄœė íŠļė—ė„œëŠ” 만ë̌ ė‹œė ė„ 따로 ė •í•īėĢžė§„ ė•Šė•˜ë‹Ī.

(3) secretęģž ë°ėī터ëē ėīėŠĪ url ëģīí˜ļ

ëģīė•ˆė„ ėœ„í•ī secretęģž ë°ėī터ëē ėīėŠĪ urlė€ ëģīėīė§€ ė•Šë„ëĄ ëģīí˜ļ되ė–īė•ž 한ë‹Ī.

app.use(session({
  secret: "Hello!",
  resave: false,
  saveUninitialized: false,
  store: MongoStore.create({ mongoUrl: "mongodb://127.0.0.1:27017/wetube" }),
}));

secretėī란 ė„œëē„ę°€ ëļŒëžėš°ė €ė— ėŋ í‚ĪëĨž ėĪŽë‹Ī는 ęēƒė„ ėĶëŠ…í•˜ęļ° ėœ„í•ī sign 할 때 ė‚ŽėšĐ하는 stringė„ 말한ë‹Ī.
ę·ļ런데 누ęĩ°ę°€ secretė„ ėīėšĐí•ī ėŋ í‚ĪëĨž 훔ėģ ëģļėļėī ę·ļ userėļė–‘ 할 눘 ėžˆęļ° ë•ŒëŽļ뗐(session hijack: ė„ļė…˜ ë‚Đėđ˜) secretė€ ęļļęēŒ ëŽīėž‘ėœ„ëĄœ 만ë“Īė–ī ė™ļëķ€ė— ë…ļėķœë˜ė§€ ė•Šë„ëĄ í•īė•ž 한ë‹Ī.

한íŽļ, 데ėī터ëē ėīėŠĪ는 user뗐 대한 ė •ëģīëĨž 氀맀ęģ  ėžˆėœžëŊ€ëĄœ 데ėī터ëē ėīėŠĪ url 또한 ė™ļëķ€ė— ë…ļėķœë˜ė–īė„œëŠ” ė•ˆëœë‹Ī.

.env íŒŒėž ėƒė„ą

ėīëĨž ėœ„í•ī 환ęē― ëģ€ėˆ˜ëĨž 만ë“Īė–ī ė―”ë“œė— ë“Īė–ī가ëĐī ė•ˆë  ë‚īėšĐë“Īė„ ėķ”가할 눘 ėžˆë‹Ī.
í”„ëĄœė íŠļ íī더(package.json íŒŒėžėī ėžˆëŠ” ęģģ)뗐 .env íŒŒėžė„ ėķ”ę°€í•œ 후 .gitignore íŒŒėžė— .envëĨž ėķ”ę°€í•œë‹Ī.
.env íŒŒėžė— ėķ”ę°€í•˜ëŠ” ę°’ė€ ęī€ėŠĩė ėœžëĄœ ëŠĻ두 대ëŽļėžëĄœ 렁ė–īė•ž 한ë‹Ī.

// .env
COOKIE_SECRET=sdfjslkfjfoj23orjasfjslafsf9f
DB_URL=mongodb://127.0.0.1:27017/wetube

dotenv ė„Īėđ˜ 및 ė‚ŽėšĐ

dotenv는 .env íŒŒėžė„ ė―ė–ī ę°ę°ė˜ ëģ€ėˆ˜ë“Īė„ process.env ė•ˆėœžëĄœ ë„Ģė–īėĪ€ë‹Ī.
ė„Īėđ˜ 후 가ëŠĨ한 한 ëđĻëĶŽ(íŒŒėžė˜ ėœ„ėŠ―ė—ė„œ) ė‚ŽėšĐ하도록 한ë‹Ī.

$ npm i dotenv

가ëŠĨ한 한 ė•ą íŒŒėžė˜ 가ėžĨ ėœ„ėŠ―ė—ė„œ import 하도록 한ë‹Ī.
í˜„ėžŽ í”„ëĄœė íŠļė˜ ęē―뚰 server.js뙀 init.js íŒŒėžė„ ëķ„ëĶŽí–ˆęļ° ë•ŒëŽļ뗐 ė‹Īė œëĄœ ė•ąė„ ė‹Īí–‰ė‹œí‚Ī는 init.js íŒŒėžė˜ 가ėžĨ ėœ„ėŠ―ė—ė„œ import í•īėĢžė—ˆë‹Ī.

// init.js
import "dotenv/config";
import "./db";
// ėī하 ėƒëžĩ

process.env

ėī렜 process.envëĨž ėīėšĐí•ī .env 값ë“Ī뗐 ė ‘ę·ží•ī ė‚ŽėšĐ할 눘 ėžˆë‹Ī.

// server.js
app.use(session({
  secret: process.env.COOKIE_SECRET, // ėˆ˜ė • ❗
  resave: false,
  saveUninitialized: fasle,
  store: MongoStore.create({ mongoUrl: process.env.DB_URL }); // ėˆ˜ė • ❗
}));
// db.js
mongoose.connect(process.env.DB_URL); // ėˆ˜ė • ❗

âœĻ ë‚īėž 할 ęēƒ

  1. ę°•ė˜ ęģ„ė† ë“Ģęļ°
profile
dev log

0ę°œė˜ 댓ęļ€