passport.js [ node.js ]

2023. 7. 27. 21:22node.js

왜 passport 로그인을 사용할까?

 

passport.js 는 서비스가 다양한 로그인을 동시에 사용해야할 때, 즉 strategy 만 짜면 나머지는 하면 알아서 된다.

 

req.user 를 만들어 주는 것, 매번 세션 검증해주는 것 등이 내부에서 저절로 구현되기 때문에 사용한다.

 

1. 다양한 인증 전략 지원

 

passport.js 는 500개가 넘는 인증 전략을 지원한다. 이는 소셜로그인, OAuth, OpenID 등 다양한 인증 방법을 통일된 API 로 사용할 수 있게 해준다. 즉 인증 전략이 변경되거나 추가되어도 일관된 코드 구조를 유지할 수 있다.

 

2. 유연성과 확장성

 

passport.js 는 단지 인증 메커니즘을 제공하는 미들웨어일 뿐, 세션 관리나 사용자 데이터 관리 등을 직접적으로 다루지는 않는다. 따라서 필요에 따라 애플리케이션에 맞게 유연하게 확장할 수 있다.

 

3. 커뮤니티 지원과 안정성

 

passport.js 는 넓은 사용자 기반과 잘 문서화된 커뮤니티를 가지고 있다. 이는 문제가 발생했을 때 도움을 받기 쉽고, 많은 개발자들에게 검증된 안정적인 라이브러리를 사용할 수 있다는 것을 의미한다.

 

https://www.passportjs.org/

 

Passport.js

Simple, unobtrusive authentication for Node.js

www.passportjs.org

https://www.npmjs.com/package/passport

 

passport

Simple, unobtrusive authentication for Node.js.. Latest version: 0.6.0, last published: a year ago. Start using passport in your project by running `npm i passport`. There are 4819 other projects in the npm registry using passport.

www.npmjs.com

 


작성한 local-strategy

 

// app.js

// ...
const session = require("express-session");
const passport = require("./passport/local-passport");

// ...

app.use(
  session({
    secret: process.env.SESSION_SECRET, // 세션 ID 를 서명하는데 사용되는 키
    resave: false, // 세션을 강제로 다시 저장할지 여부를 결정
    saveUninitialized: false, // 초기회 되지 않은 세션을 저장소에 저장할지 여부를 설정
    cookie: {
      httpOnly: true,
      secure: false,
      sameSite: "strict",
    },
  })
);

// ...

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

// ...

 

// local-passport.js

const passport = require("passport");
const LocalStrategy = require("passport-local").Strategy; // 로컬 전략 설정
const bcrypt = require("bcrypt"); // bcrypt 를 통한 암호화
const { Users } = require("../models");

passport.use(
  new LocalStrategy(
    {
      usernameField: "email", // html 의 name 과 같아야한다.
      passwordField: "password", // html 의 name 과 같아야한다.
    },
    async (email, password, done) => {
      try {
        const user = await Users.findOne({ where: { email } }); // 유저가 있는지 확인

        if (!user) {
          return done(null, false, { errorMessage: "잘못된 이메일입니다." });
        }
        if (!bcrypt.compareSync(password, user.password)) {
          return done(null, false, { errorMessage: "잘못된 비밀번호입니다." });
        }
        return done(null, user); // 성공한 경우
      } catch (err) {
        return done(err);
      }
    }
  )
);

passport.serializeUser((user, done) => { // 직렬화, pasport.authenticate 이후 세션 기록(serializeUser)
  done(null, user.userId); // 인증 성공 → 세션 기록, user 는 인증과정에서 얻어낸 사용자 정보
});

passport.deserializeUser(async (id, done) => { // 역직렬화, 일반 요청마다 세션에서 읽기(descrializeUser)
  try { // 클라이언트 요청 → 세션에서 인증 정보 읽기
    const user = await Users.findByPk(id);
    done(null, user); // req.user 로 전달
  } catch (err) {
    done(err);
  }
});

module.exports = passport;

 

// login.controller.js

const LoginService = require("../services/login.service");
const passport = require("passport");
const jwt = require("jsonwebtoken");
require("dotenv").config();

class LoginController {
  loginService = new LoginService();

  loginUser = async (req, res, next) => {
    passport.authenticate("local", (err, user, info) => { // 인증 요청
      if (err) {
        console.log(err);
        next(err);
      }
      if (!user) {
        return res.status(401).json({ errorMessage: info.errorMessage });
      }

      req.logIn(user, (err) => {
        if (err) {
          console.log(err);
          return next(err);
        }

        const token = jwt.sign(
          { userId: user.userId },
          process.env.JWT_SECRET,
          {
            expiresIn: "1h",
          }
        );

        res.cookie("cowdog", `Bearer ${token}`);

        return res.status(200).json({ message: "로그인 성공", token });
      });
    })(req, res, next);
  };
}

module.exports = LoginController;

 


자세한 내용은 노션

 

https://overjoyed-sailfish-366.notion.site/passport-js-c6f79738afed4d58ac3d800b5c376441?pvs=4 

 

passport.js

서비스 내 직접 인증 기능 (Local Auth)

overjoyed-sailfish-366.notion.site


마치며

 

추가적으로 지금 현재 passport 내부에서 express-session 을 이용하기 때문에 따로 핸들링을 하지 않아서 메모리에 저장된다.

이 떄문에 스케일링 시에 이슈가 생길 수 있으므로 나중에 redis 를 사용해 옮겨야 한다.

 

스케일링 이란?

"스케일링"은 시스템이 요구 사항이나 부하에 따라서 성능을 유지하거나 개선할 수 있는 능력을 가리킵니다. 이는 사용자의 수가 증가하거나 데이터의 양이 늘어남에 따라 시스템의 처리 용량을 늘릴 수 있는 능력을 의미합니다.

스케일링 문제 란?

"스케일링 문제"는 시스템의 처리 능력이 요구사항을 충족시키지 못하게 될 때 발생합니다. 이는 보통 요청을 처리하는 데 걸리는 시간이 늘어나거나, 처리할 수 있는 요청의 수가 줄어들게 되는 결과를 초래합니다.

 

 

'node.js' 카테고리의 다른 글

에러처리 미들웨어 [ express ] [ node.js ]  (0) 2023.07.22
multer  (0) 2023.07.20
JWT 토큰 [ node.js ] [ express ]  (0) 2023.07.16
bcrypt 사용방법 [ Javascript ] [ node.js ]  (0) 2023.07.07
PM2 사용  (0) 2023.06.24