[express] 세션(session) 방식 로그인, 인증 구현(ft. connect-mongo)

박기영·2022년 10월 10일
0

Express

목록 보기
1/2

문제 상황

필자는 프론트엔드 직무를 목표로 공부하는 사람이지만, 백엔드 쪽을 구현해야할 때가 있다.
아마, 혼자서 프로젝트를 만들다보면 그렇게 될 것이다.
필자는 연합동아리에서 떨어지고, 부트캠프는 하고있지 않기에, 혼자서 모든걸 구현해야할 때가 많다.
그렇게 유저 인터랙션의 기본이 되는 로그인 기능을 구현하기 위해 백엔드 쪽 공부를 하다가,
express-session을 활용한 로그인, 인증 방법을 몇 주에 걸쳐 삽질을 통해 구현했는데, 까먹지 않기위해 기록하고자한다.(완벽하지는 않지만 ㅠㅠ)

세션을 활용하는 로그인 방식은
세션을 쿠키에 저장하는 법, 파일에 저장하는 법, DB에 저장하는 법으로 크게 나뉜다.
필자는 처음에는 파일에 저장하는 법으로 구현을 했는데,
배포 후 작동이 안되는 문제가 발생해서, DB에 저장하는 방법으로 다시 개발 중이다.
따라서, DB에 저장하는 방법을 작성하고자 한다.

주요 라이브러리

"connect-mongo": "^4.6.0",
"express": "^4.18.1",
"express-session": "^1.17.3",
"mongoose": "^6.6.3"

코드

세션 틀 제작

// index.js

const config = require("./config/key");
const session = require("express-session");
const MongoStore = require("connect-mongo");

app.use(
  session({
    secret: config.cookieSecret,
    resave: false,
    saveUninitialized: false,
    store: MongoStore.create({
      mongoUrl: config.mongoURI,
    }),
    cookie: { maxAge: 3.6e6 * 24 }, // 24시간 뒤 만료(자동 삭제)
  })
);

store 부분이 DB에 세션을 저장하기 위한 방법이다.

로그인 시 세션 생성

세션의 틀만 만들면 의미가 없다.
세션을 생성해야지 비로소 그 것을 활용할 수 있다.

그러면..언제 세션이 생성되면 될까?

필자는 유저가 로그인했을 때가 그 때라고 생각한다.

보통 세션이 유저 정보의 요청 등에 사용되기 때문에,
로그인하지 않은 유저는 굳이 세션이 필요 없다고 보기 때문이다.
물론 이 부분은 어떤 서비스를 만드냐에 따라서 변경될 수 있다.

필자는 로그인된 유저에게만 세션을 사용할 것이므로,
로그인 시 세션이 생성되게 코드를 작성했다.

// index.js

// 로그인 라우터
app.post("/api/users/login", (req, res) => {
  User.findOne({ email: req.body.email }, (err, user) => {
    if (!user) {
      return res.json({
        loginSuccess: false,
        message: "입력된 이메일에 해당하는 유저가 없습니다.",
      });
    }

    user.comparePassword(req.body.password, (err, isMatch) => {
      if (!isMatch) {
        return res.json({
          loginSuccess: false,
          message: "비밀번호가 틀렸습니다.",
        });
      }

      // 아이디, 비밀번호 일치 시 유저 정보가 들어있는 세션 생성
      req.session.email = req.body.email;
      req.session.nickname = user.nickname;
      req.session.logined = true;
      req.session.role = user.role;

      return res.status(200).json({
        loginSuccess: true,
        email: req.session.email,
        nickname: req.session.nickname,
        profile: user.profile,
      });
    });
  });
});

위 코드에서 세션이 생성되기 시작하는 부분은 req.session이 작성되는 부분이다.
그 외에는 개발하는 분에 따라 코드가 달라질 것이다.

req.session.email에 값을 넣으면
해당 key-value가 세션에 추가된다.

아래는 req.session을 콘솔로 찍어본 것이다.

위 코드에서 입력해준 것들이 그대로 아래에 보이는 것을 확인 할 수 있다.
또한, 세션 틀을 만들 때 지정해놓은 기본 값들도 cookie라는 곳에 들어가있다.

자, 유저 로그인이라는 이벤트가 발생했을 때 세션을 생성해냈다.
이를 어떻게 활용하면 좋을까?

세션을 통한 인증

다양한 웹/앱을 이용하다보면 세션이 만료되었습니다. 다시 시도해주세요 같은 문장을 가끔 볼 수 있다.

지금까지 구현해본 세션의 형태를 생각해보면,
만료라는 것은 아무래도 req.session에서 확인했던 cookie와 관련이 있는 것 같다.

cookie에 명시된 시간이 지나면 발행된 세션의 유효기간이 만료되기 때문이다.

아무튼, 세션이 유효하다는 것은
세션을 생성한 유저의 정보에 접근할 수 있는 방법이 유효하다는 것과 같게 볼 수 있겠다.

이를 이용해서 인증을 구현할 것이다.
인증 기능은 아래와 같은 상황에서 주로 쓰인다고 생각한다.

  1. 유저의 로그인 여부 판별
  2. 일반 유저와 관리자 판별

필자는 프로젝트에서 두 기능을 많이 사용했다.

// index.js

// 인증 라우터
const { auth } = require("./middleware/auth");

app.get("/api/users/auth", auth, (req, res) => {
  res.status(200).json({
    // user.role이 0이라면 일반유저, 1이라면 관리자 유저를 의미한다.
    isAdmin: req.user.role === 0 ? false : true,
    isAuth: true,
    email: req.session.email,
    nickname: req.session.nickname,
    authSuccess: true,
  });
});

auth라는 커스텀 미들웨어를 거쳐서,
통과한다면 인증된 유저로서 활동할 수 있도록 isAuthtrue로 해줬다.

auth 미들웨어는 다음과 같다.

// middleware/auth.js

const { User } = require("../model/User");

const auth = (req, res, next) => {
  if (req.session.logined) {
    // req.session 정보에 들어가 있는 유저를 인증 유저로 설정
    req.user = req.session;

    next();
  } else {
    return res.json({ isAuth: false, authSuccess: false });
  }
};

module.exports = { auth };

isAuthisAdmin을 적절히 활용하여
위에서 말한 1,2번 기능을 구현하면 된다.

isAuth는 1번 기능에서,
isAdmin은 2번 기능에서 활용한다.

참고 자료

참고 자료 1
참고 자료 2
참고 자료 3
참고 자료 4
참고 자료 5
참고 자료 6
참고 자료 7
참고 자료 8
참고 자료 9
⬇️ connet-mongo 관련 참고 자료
leitmotif님 블로그
bsnow님 블로그
망고좋아님 블로그
개발자님 블로그
eggs30님 블로그
devsr님 블로그
포시님 블로그
운동개발좋아님 블로그
ha0님 블로그

profile
나를 믿는 사람들을, 실망시키지 않도록

0개의 댓글