우리가 쓰는 HTTP,UDP 등의 프로토콜은 '무상태(Stateless)'한 성질을 갖고있다.
서버가 클라이언트의 세션상태/정보를 기억하지 못한다는 뜻이다.
그래서 서버는 클라이언트(브라우저)의 요청에 대한 응답(response)만 해주고 통신을 종료한다.
서버가 클라이언트의 상태를 기억하지 못하기때문에 클라이언트 입장에서는 자기자신을 매번 서버에 검증받아야한다.
이때 클라이언트는 본인만의 인증증표가 있다면 서버입장에서는 해당 클라이언트에 대한 확인이 쉬워질거다 (인증)
서버가 클라이언트(브라우저)를 기억하기위해 '쿠키'에 고유한 ID인 세션ID를 담아서 클라이언트의 최초요청시에 같이 보내주고. (이것이 그 증표역할)
(saveUninitialized 옵션으로 세션데이터의 변경점만 있을때에만 보내주게끔 해줄수는 있다)
클라이언트는 쿠키의 특성상 세션아이디가 담긴 쿠키를 매 요청시마다 헤더에 껴서 보낼거다.
그럼 서버는 해당 쿠키를 까서 세션아이디를 보고 서버에 있는 세션데이터를 넘겨주거나 할것이다.
express 내에서 세션기능을 쓸수 있게 하는 미들웨어
=> 쿠키에 세션ID를 넣는게 아닌 데이터 전체를 넣고싶으면 cookie-session이란 미들웨어를 사용해야한다.
import session from "express-session";
app.use(session({
secret:process.env.COOKIE_SECRET,
store: myStorem
resave:false,
saveUninitialized:false
}))
각옵션을 뜯어보자면
새로고침시 (서버/클라의 재시작) 마다 store가 기본값인 memoryStore라면 세션을 비울테니 이를 db와 연동해서 보관해야할거다.
몽고db를 예로들자면
import session from 'express-session'
import MongoStore from 'connect-mongo'
app.use(session({
secret:process.env.COOKIE_SECRET,
store: MongoStore.create({client:mongoose.connection.client})
resave:false,
saveUninitialized:false
}))
mongoDB와 store를 연동하고싶으면 공식문서에 나온것처럼 'connect-mongo'패키지를 설치후 사용법을 따르면 된다.
MongoStore.create메서드 안에는 MongoClient나 mongoDB의 URL을 받아서 연동시키는데.
이미 url을 이용해 mongoose와 연동을 시켰다면 MongoClient가 생성되어 있을거고 해당 client를 이용해서 세션스토어를 해당 mongoDB에 연동시키면 될거다.
app.use로 글로벌 미들웨어로 써주고 상단에 위치하게 되면 최초 요청시에(saveUninitialized:true 라는 가정하에) 서버는 쿠키에 sessionID를 담아서 브라우저한테 넘기고 세션스토어에 해당 브라우저정보를 저장할거다
app.use((req,res,next) => {
console.log(req.sessionStore) // check session Store
req.sessionStore.all((err,sessions) => {
console.log('seesions',sessions);
next();
})
//모든 세션(연결)들을 볼수있음
req.session.customData +=1 ;
})
이후 세션에 커스텀 데이터를 추가할수 있다 (만약 saveUninitialized:false라면 이때 세션스토어에 세션이 저장될거다. -> 생성후 추가적인 데이터 커스텀이 생겼을때 저장하는 옵션이니까)
if(isLogin){
req.session.isLogin = true;
req.session.user = user;
}
유저가 로그인상태일때 세션데이터를 넣어주는 예시.
커스텀 세션데이터가 있다는것은 현재 브라우저가 연결되있다는 소리고. 이제 커스텀데이터를 브라우저에게 보여줘야한다. 이때 템플릿엔진에 세션데이터를 넘겨줘야하는데 이때 response.locals를 쓴다
이 속성을 사용하면 response.render에 쓰이는 템플릿에서 접근가능한 변수를 세팅해줄수 있다. 즉 res.locals안에 세션데이터를 넣어주면 템플릿엔진에서 세션데이터에 접근이 가능한거다.
app.use((req,res,next) => {
//경로가 없으면 전역적으로 세팅되는 미들웨어
const {isLogin,user} = req.session
res.locals.isLogin = Boolean(isLogin)
if(isLogin){
res.locals.user = user;
}
next();
})
템플릿 엔진 쪽에서는 user라고만 참조하면 된다. 그리고 모~든 템플릿에서 전역적으로 참조할수 있다. 마찬가지로 미들웨어로써 최종response하기 전에 로그인검사후 세팅해주는모습.
미들웨어로써 처리했으니 순서가 중요할거다 session을 만들기도 전에 session을 참조하는 미들웨어가 먼저 선언되어 있다거나 등.