express-passport (local login 구현)

김민석·2021년 6월 12일
1

express

목록 보기
3/4
post-thumbnail

클론코딩의 장점은 앞서간 사람의 깔끔한 코드를 볼 수 있다는 것이다.
그러나 단점은 새로운 스택 등이 나왔을 때, 자칫 겉만 핥은 채로 넘어갈 수 있다는 것이다.
그것을 주의해야한다.


express에서 passport를 사용하여 local login 구현하기

참고

아래의 코드는 passport 사이트에서 찾은 참고 코드다.

var express = require('express');
var passport = require('passport');
var Strategy = require('passport-local').Strategy;
var db = require('./db');


// Configure the local strategy for use by Passport.
//
// The local strategy requires a `verify` function which receives the credentials
// (`username` and `password`) submitted by the user.  The function must verify
// that the password is correct and then invoke `cb` with a user object, which
// will be set at `req.user` in route handlers after authentication.
passport.use(new Strategy(
  function(username, password, cb) {
    db.users.findByUsername(username, function(err, user) {
      if (err) { return cb(err); }
      if (!user) { return cb(null, false); }
      if (user.password != password) { return cb(null, false); }
      return cb(null, user);
    });
  }));

// Configure Passport authenticated session persistence.
//
// In order to restore authentication state across HTTP requests, Passport needs
// to serialize users into and deserialize users out of the session.  The
// typical implementation of this is as simple as supplying the user ID when
// serializing, and querying the user record by ID from the database when
// deserializing.
passport.serializeUser(function(user, cb) {
  
  // 모든 정보를 저장하는 것은 사용자 정보가 크다면, 메모리가 많이 소모되기 때문에,
  // id만 저장하고, 이후 deserialize시에 id를 이용하여 db에서 유저를 확인함.
  cb(null, user.id);
});

passport.deserializeUser(function(id, cb) {
  db.users.findById(id, function (err, user) {
    if (err) { return cb(err); }
    cb(null, user);
  });
});

// Create a new Express application.
var app = express();

// Use application-level middleware for common functionality, including
// logging, parsing, and session handling.

app.use(passport.initialize());
app.use(passport.session());

  
app.post('/login', 
  passport.authenticate('local', { failureRedirect: '/login' }),
  function(req, res) {
    res.redirect('/');
  });
  

app.listen(3000);

이를, 제로초는 다음과 같이 구현했다.

//app.js
const express = require("express");
const app = express();

const passportConfig = require("./passport");

passportConfig();

app.use('garadori')

...[후략]
// passport/index.js
const passport = require("passport");
const local = require("./local");
module.exports = () => {
  passport.serializeUser(() => {});
  passport.deserializeUser(() => {});
  local();
};
// passport/local.js
const passport = require("passport");
const { Strategy: LocalStrategy } = require("passport-local");
const { User } = require("../models");

module.exports = () => {
  passport.use(
    new LocalStrategy(
      {
        usernameField: "email",
        passwordField: "password",
      },
      async (email, password, done) => {
        try {
          const user = await User.findOne({
            where: { email },
          });
          if (!user) {
            done(null, false, { reason: "존재하지 않는 이메일입니다!" });
          }
          const result = await bcrypt.compare(password, user.password);
          if (result) {
            return done(null, user);
          }
          return done(null, false, { reason: "비밀번호가 틀렸습니다." });
        } catch (err) {
          console.error(err);
          return done(err);
        }
      }
    )
  );
};

// routes/user.js

router.post("/login", (req, res, next) => {
  passport.authenticate("local", (err, user, info) => {
    if (err) {
      console.error(err);
      return next(err);
    }
    if (info) {
      return res.status(401).send(info.reason);
    }
    

    return req.login(user, async (loginErr) => {
      if (loginErr) {
        console.log(loginErr);
        return next(loginErr);
      }
      return res.status(200).json(user);
    });
  })(req, res, next);
});

참고

  • passport.authenticate를 사용하는 방식이 맨 윗 코드와 다르다.(윗 코드는 middleware 위치에 들어갔지만, 제로초 코드는 route handler 내부에서 실행되고 있다.)
    이유는 여기를 보면 '맨 아래' 다음과 같은 부분이 있다.
  • 'local'이라는 string strategy에 따라 정해진다. 예를 들어 twitter-strategy를 사용하기 위해 npm install pass-twitter를 하여 import 후 새로운 strategy를 만든다면, 해당 전략을 사용하기 위해 passport.authenticate('twitter',...)를 하면 된다.

이렇게 구현하면, app.js에 모든 코드를 다 몰아넣었던 처음코드와 달리,
모듈화 할 수 있다는 것을 배웠다. (원리를 아는 것과 사용하는 것은 역시 거리가 멀다...)😵‍💫😵‍💫😵‍💫

0개의 댓글