express-session

길고 꾸준하게·2022년 5월 26일
0
post-thumbnail

Stateless

우리가 쓰는 HTTP,UDP 등의 프로토콜은 '무상태(Stateless)'한 성질을 갖고있다.

서버가 클라이언트의 세션상태/정보를 기억하지 못한다는 뜻이다.
그래서 서버는 클라이언트(브라우저)의 요청에 대한 응답(response)만 해주고 통신을 종료한다.

서버가 클라이언트의 상태를 기억하지 못하기때문에 클라이언트 입장에서는 자기자신을 매번 서버에 검증받아야한다.

이때 클라이언트는 본인만의 인증증표가 있다면 서버입장에서는 해당 클라이언트에 대한 확인이 쉬워질거다 (인증)


서버가 클라이언트(브라우저)를 기억하기위해 '쿠키'에 고유한 ID인 세션ID를 담아서 클라이언트의 최초요청시에 같이 보내주고. (이것이 그 증표역할)

(saveUninitialized 옵션으로 세션데이터의 변경점만 있을때에만 보내주게끔 해줄수는 있다)

클라이언트는 쿠키의 특성상 세션아이디가 담긴 쿠키를 매 요청시마다 헤더에 껴서 보낼거다.
그럼 서버는 해당 쿠키를 까서 세션아이디를 보고 서버에 있는 세션데이터를 넘겨주거나 할것이다.

express-session

express 내에서 세션기능을 쓸수 있게 하는 미들웨어
=> 쿠키에 세션ID를 넣는게 아닌 데이터 전체를 넣고싶으면 cookie-session이란 미들웨어를 사용해야한다.

usage / option

import session from "express-session";

app.use(session({
   secret:process.env.COOKIE_SECRET,
   store: myStorem
   
   resave:false,
   saveUninitialized:false
}))

각옵션을 뜯어보자면

  • secret : 쿠키를 암호화하는데 사용되는 키 -> 이 키가 간단하지 않을수록 보안에 좋겠지?
  • store : 세션데이터를 저장하는 장소. default는 MemoryStore다
  • resave : 세션의 변경사항이 없어도 새로 저장하게 하는 옵션. default는 true지만 대부분의 경우에는 false를 사용한다.
  • saveUninitialized : Uninitialized한 세션을 강제로 저장함 default는 true다.
  1. store의 기본값인 MemoryStore는 기본적으로 출시단계를 위해 설계된 store가 아니다.
    그렇기때문에 서버/클라이언트를 재시작하면 세션데이터가 날아간다. 이는 로그인등을 세션데이터로 다룰때에 로그인된 유저가 전부 로그아웃 될 가능성이 있는 것이다.
    그렇기때문에 출시 환경에서는 MemoryStore가 아닌 다른 store를 써야하며. 그 종류는 다음 링크에 있다.
    https://github.com/expressjs/session#compatible-session-stores
  2. uninitialized한 세션이란 '새로 생성된' 세션에 아무런 작업이 이루어지지 않은 상황을 말한다.
    즉 생성후에 아무런 세션데이터가 없는 초기상태를 말한다. 즉 saveUninitialized옵션은 완전갓태어난 세션도 세션스토어에 저장할지를 정하는건데. 예를 들만한 상황은
    /
    로그인시에 세션데이터를 넘겨주고싶은데 위 옵션을 true로 설정하면 로그인 하지도 않은 유저에게 sessionID를 담아서 쿠키를 보내고 해당 세션을 저장할거다. / 이는 보안상에도 좋지않고 세션스토어의 용량을 아낄수 있기때문에 false를 써준다 /

store -> mongoDB

새로고침시 (서버/클라의 재시작) 마다 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에 연동시키면 될거다.

  • mongoDB 공식문서에는 MongoClient를 이용해 몽고db에 연결하고 대화할수 있다고 한다.
  • 난 MongoClient를 만든적이 없는데? 싶을수도 있는데 mongoose.conect()가 몇가지 옵션을 제외하고 MongoDB의 new MongoClient -> MongoClient.connect()까지 해주는거다

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.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을 참조하는 미들웨어가 먼저 선언되어 있다거나 등.

profile
작은 나의 개발 일기장

0개의 댓글