프로그래밍 언어/NODE JS

Passport 모듈로 로그인 구현하기

· 코딩마이데이

SNS 서비스이므로 회원가입과 로그인이 필요합니다. 회원가입과 로그인을 직접 구현할 수도 있지만, 세션과 쿠키 처리 등 복잡한 작업이 많으므로 검증된 모듈을 사용하는 것이 좋습니다. 바로 Passport를 사용하는 것입니다.이 모듈은 이름처럼 우리의 서비스를 사용할 수 있게 해주는 여권 같은 역할을 합니다.

요즘에는 서비스에 로그인할 때 아이디와 비밀번호를 사용하지 않고 구글, 페이스북, 카카오톡 같은 기존의 SNS 서비스 계정으로 로그인하기도 합니다. 이 또한 Passport를 사용해서 해결할 수 있습니다.

 

먼저 Passport 관련 패키지들을 설치합니다.

$ npm i passport passport-local passport-kakao bcrypt

 

app.js

const express = require("express");
const cookieParser = require("cookie-parser");
const morgan = require("morgan");
const path = require("path");
const session = require("express-session");
const nunjucks = require("nunjucks");
const dotenv = require("dotenv");
const passport = require("passport");

dotenv.config();
const pageRouter = require("./routes/page");
const { sequelize } = require("./models");
const passportConfig = require("./passport");

const app = express();
passportConfig(); // 패스포트 설정
app.set("port", process.env.PORT || 8001);
app.set("view engine", "html");
nunjucks.configure("views", {
  express: app,
  watch: true,
});
sequelize
  .sync({ force: false })
  .then(() => {
    console.log("데이터베이스 연결 성공");
  })
  .catch((err) => {
    console.error(err);
  });

app.use(morgan("dev"));
app.use(express.static(path.join(__dirname, "public")));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser(process.env.COOKIE_SECRET));
app.use(
  session({
    resave: false,
    saveUninitialized: false,
    secret: process.env.COOKIE_SECRET,
    cookie: {
      httpOnly: true,
      secure: false,
    },
  })
);
app.use(passport.initialize());
app.use(passport.session());

app.use("/", pageRouter);

app.use((req, res, next) => {
  const error = new Error(`${req.method} ${req.url} 라우터가 없습니다.`);
  error.status = 404;
  next(error);
});

app.use((err, req, res, next) => {
  res.locals.message = err.message;
  res.locals.error = process.env.NODE_ENV !== "production" ? err : {};
  res.status(err.status || 500);
  res.render("error");
});

app.listen(app.get("port"), () => {
  console.log(app.get("port"), "번 포트에서 대기중");
});

 

require('./passport')는 require('./passport/index.js')와 같습니다. 폴더 내의 index.js 파일은 require 시 이름을 생략할 수 있습니다.

passport.initialsize 미들웨어는 요청(req 객체)에 passport 설정을 심고, passport.session 미들웨어는 req.session 객체에 passport 정보를 저장합니다. req.session 객체는 express-session에서 생성하는 것이므로 passport 미들웨어보다 뒤에 연결해야 합니다.

passport 폴더 내부에 index.js 파일을 만들고 Passport 관련 코드를 작성해봅시다.

 

passport/index.js

const passport = require("passport");
const local = require("localStrategy");
const kakao = require("./kakaoStrategy");
const User = require("./models/user");

module.exports = () => {
  passport.serializeUser((user, done) => {
    done(null, user.id);
  });

  passport.deserializeUser((id, done) => {
    User.findOne({ where: { id } })
      .then((user) => done(null, user))
      .catch((err) => done(err));
  });

  local();
  kakao();
};

 

1. 라우터를 통해 로그인 요청이 들어옴

2. 라우터에서 passport.authenticate 메서드 호출

3. 로그인 전략 수행

4. 로그인 성공 시 사용자 정보 객체와 함께 req.login 호출

5. req.login 메서드가 passport.serializeUser 호출

6. req.session에 사용자 아이디만 저장

7. 로그인 완료

 

로그인 이후의 과정은

1. 요청이 들어옴

2. 라우터에 요청이 도달하기 전에 passport.session 미들웨어가 passport.deserializeUser 메서드 호출

3. req.session에 저장된 아이디로 데이터베이스에서 사용자 조회

4. 조회된 사용자 정보를 req.user에 저장

5. 라우터에서 req.user 객체 사용 가능

입니다.