1. Cookie Session (1)
- 이전까지는 account가 존재하는지, account의 password가 맞는지만 확인하였음
- 이제는 서버가 로그인을 시도한 유저를 기억하는 방법을 알아야 함
- 그 방법 중 하나가 cookie이며, cookie를 이해하기 전 먼저 session에 대해 알아야 함
- session이란, 백엔드와 브라우저 간에 어떤 활동(history)을 했는지 기억(memory)하는걸 말함
- 백엔드와 브라우저간 정보가 있어야 됨
- 현재 home으로 이동하면 GET request가 발생하는데, 백엔드에서 HTML을 render하고 나면 연결이 끝남
- 즉 연결이 지속되지 않는 무상태(stateless)
- request를 받고 처리되면 서버도 브라우저도 곧바로 잊어버리게 됨
- 유저가 백엔드에 뭔가 request를 보낼 때마다 누가 request하는지 알 수 있게 어떤 정보를 남겨야 함
2. Express-Session
- https://www.npmjs.com/package/express-session
express-session
Simple session middleware for Express. Latest version: 1.18.1, last published: a month ago. Start using express-session in your project by running `npm i express-session`. There are 5034 other projects in the npm registry using express-session.
www.npmjs.com
- express-session이라는 middleware를 사용하여 session을 처리
- 설치하고 server.js에 router 앞에 초기화
// server.js
import session from "express-session";
app.use(
session({
secret: "hello",
resave: true,
saveUninitialized: true,
})
);
- 나중에는 secret을 아무도 모르는 문자열로 만들 예정
- console에 undefined 메세지가 2개 출력되므로 그 부분도 함께 수정했음
- 이제부터 session middleware는 사이트로 들어오는 모든 것들을 기억
- 들어오는 모든 대상에게 어떤 텍스트를 주고 그 텍스트를 가지고 유저가 누구인지 판단
- 개발자 도구 > application > cookies에 cookie가 생성된 것을 볼 수 있음
- 백엔드에 request를 보낼 때 마다, 브라우저가 알아서 백엔드에 cookie를 보냄
- middleware를 하나 만들어서 이해를 해봄
// server.js
app.use((req, res, next) => {
console.log(req.headers);
next();
});
// result
cookie: 'connect.sid=s%3AIYv4Nc~~~~~~~~
- 이 텍스트의 내용을 알아보기 위해 middleware 수정
// server.js
app.use((req, res, next) => {
req.sessionStore.all((error, sessions) => {
console.log(sessions);
next();
});
});
// result
[Object: null prototype] {
'1RLzqNUI~~~~~~~~~~~~': {
cookie: { originalMaxAge: null, expires: null, httpOnly: true, path: '/' }
}
}
- 백엔드에 1RLz로 시작하는 session이 있다고 알려줌
- 접속한 사람이 사용하는 브라우저에서의 id가 1RLz로 시작한다는 뜻
- 브라우저를 바꿔서 접속해보면 cookie value가 다름
- console에 session이 2개가 출력되며 다른 부라우저의 cookie value는 OmgQ로 시작함
2. Cookie Session (2)
- 현재는 서버를 재시작하게 되면 session이 사라지게 되는데, express가 session을 메모리에 저장하고 있기 때문
- 예전에 가짜 db를 만들었을 때와 비슷한 상황
- 차후에 백엔드가 잊지 않도록 session을 mongoDB와 연결
- 이제 백엔드가 쿠키를 가지고 어떻게 브라우저를 구분하는지 확인
- 1번에서는 백엔드가 브라우저한테 우리가 이해할 수 없는 텍스트를 보내는걸 봤음
- 이 텍스트는 백엔드에서 session id로 사용되고 있었음
- 백엔드의 메모리에 session을 저장할 수 있는 db가 생긴 것
- 백엔드의 각 session들은 id를 가지고 있었고 id를 브라우저에 보냄
- 그러면 브라우저가 request를 보낼 때 마다 id를 같이 보내주고 브라우저와 일치하는 session이 뭔지 알 수 있음
- 서로 다른 브라우저는 서로 다른 cookie를 가지고 있고 서로 다른 session id를 가지고 있기 때문
- session id를 가지고 있으면 session object에 정보를 추가 할 수 있음
app.get("/add-one", (req, res, next) => {
req.session.potato += 1;
return res.send(`${req.session.id}\n${req.session.potato}`);
});
- 이렇게 URL을 만들고 /add-one으로 이동해보면 session id가 출력되며, 브라우저마다 다른 id가 출력
- 새로고침 할 때마다 potato가 1씩 늘어남
3. Locals Object
- server는 어떻게 보면 1초마다 까먹는 사람과 같음
- 그렇기 때문에 모든 요청으로부터 id가 필요함
- id 정보를 가진 db를 만들고, 누군가 id 카드를 가지고 찾아오면 그때 확인
- userController로 가서, 유저가 로그인하면 그 유저에 대한 session 정보를 담음
- 각 유저마다 서로 다른 req.session object를 가지고 있음
// postLogin
req.session.loggedIn = true;
req.session.user = user;
// console
// 데이터는 일부러 삭제하였음
[Object: null prototype] {
CpmV~~~~~~~~blablabla: {
cookie: { originalMaxAge: null, expires: null, httpOnly: true, path: '/' },
loggedIn: true,
user: {
_id: '',
email: '',
username: '',
password: '',
name: '',
location: '',
__v: 0
}
}
}
- object에 session id와 loggedIn, 로그인을 시도했던 유저의 user object 또한 함께 담겨있음
- 다른 브라우저로 접속하면 session이 2개 기록됨
- loggedIn을 사용하여 로그인 여부를 판단할 수 있으므로 template을 수정
- loggedIn이 true일 경우, navigation의 Join과 Login을 가리고 Log out을 보여줄거임
- 우선 template에서 session에 접근할 수 있는지 확인
// base.pug
if !req.session.loggedIn
li
a(href="/join") Join
li
a(href="/login") Login
- Cannot read properties of undefined (reading 'session') 에러 발생
- 누가 user인지는 log의 session DB 통해 알 수 있지만, 그 정보를 pug templage과 공유하지 못함
app.use((req, res, next) => {
console.log(res);
req.sessionStore.all((error, sessions) => {
console.log(sessions);
next();
});
});
- 생성해뒀던 middleware를 통해 res를 한번 살펴보면 locals가 있음
locals: [Object: null prototype] {},
- pug template에서 locals에 접근할 수 있으며 기본적으로 되는거임
- pug과 express가 서로 locals를 공유할 수 있도록 설정되어 있음
- 우리가 locals object를 바꾸면, template에서도 그 내용을 확인할 수 있음
// server.js
app.use((req, res, next) => {
res.locals.sexy = "you";
req.sessionStore.all((error, sessions) => {
console.log(sessions);
next();
});
});
// base.pug
doctype html
html(lang="ko")
head
title #{pageTitle} | Wetube
link(rel="stylesheet" href="https://unpkg.com/mvp.css")
body
header
h1 Who is sexy? #{sexy}
nav
ul
li
a(href="/") Home
li
a(href="/join") Join
li
a(href="/login") Login
li
a(href="/search") Search
li
a(href="/videos/upload") Upload Video
main
block content
include partials/footer
- 특이하게도 req.locals같은 것들을 쓰지 않고 바로 sexy를 써도 값을 받아옴
- 이런 방식으로 template과 data를 공유하며, 이 것은 global(전역변수)이기에 모든 template에서 사용가능
- 현 상태로는 어느 페이지를 가도 h1이 동일하게 나옴
- middleware를 router에 적용했을 때 한해서임
- template에 변수를 전역적으로 보낼 수 있으므로, res.render로 보내지 않아도 됨
- 즉 locals object는 모든 pug template에 import된 object
- locals object는 굉장히 유용하며, locals에 로그인한 사용자를 추가할 거임
- template이 누가 로그인 했는지 알 수 있게 되었다는 것
4. middleware.js를 사용하여 효과적인 middleware 관리
// middleware.js
export const localsMiddleware = (req, res, next) => {
res.locals.loggedIn = Boolean(req.session.loggedIn);
res.locals.siteName = "Wetube";
res.locals.loggedInUser = req.session.user;
console.log(res.locals);
next();
};
// server.js
// router 위에 있어야 함
app.use(localsMiddleware);
// console
Session {
cookie: { path: '/', _expires: null, originalMaxAge: null, httpOnly: true },
loggedIn: true,
user: {
_id: '672e1061a4693a06d0f0574e',
email: '2@2',
username: '2',
password: '$2b$05$.8yCh9vZOjTCK8YBb7LDGOCCGVtrGDk0gaUbHRLYvFWWKWFPp3HkK',
name: '2',
location: 'usa',
__v: 0
}
}
doctype html
html(lang="ko")
head
title #{pageTitle} | #{siteName}
link(rel="stylesheet" href="https://unpkg.com/mvp.css")
body
header
h1=pageTitle
nav
ul
li
a(href="/") Home
if loggedIn
li
a(href="/logout") Logout
li
a(href="/my-profile") #{loggedInUser.name}
else
li
a(href="/join") Join
li
a(href="/login") Login
li
a(href="/search") Search
li
a(href="/videos/upload") Upload Video
main
block content
include partials/footer
'개발 > Node.js' 카테고리의 다른 글
Secret Domain Expiration Etc (0) | 2024.11.12 |
---|---|
MongoStore resave saveUninitialized (0) | 2024.11.12 |
Login / Bcrypt Compare (0) | 2024.11.08 |
Status Code (0) | 2024.11.08 |
User Authentication / Hash (0) | 2024.11.07 |