bluegram - passport

박상은·2021년 12월 17일
0

🍃 blegram

목록 보기
10/20

1. passport

유저 인증 관련 처리는 passport를 이용해서 처리했습니다.
passportstrategy라는 단어를 이용해서 각 로그인 전략을 구현하도록 도와주는 라이브러리입니다.
현재는 local전략만 구현을 한 상태이고, 프론트단을 만들고 나서 kakao, naver, facebook 로그인 전략도 구현할 예정입니다.

2. passport-local의 실행흐름

간단하게 말하면
1. 로그인 엔드포인트로 요청 발생
2. 전송된 데이터로 유저 인증
3. 인증 성공 시 serializeUser를 통해서 서버의 세션에 유저의 식별자만 저장 ( 저장하는 곳은 memory file, radis 등 )
4. 인증 성공 시 req.login()에서 세션쿠키를 만들어서 브라우저에게 전달
5. 로그인 이후 다음 요청부터 세션쿠키를 받아서 deserializeUser에서 로그인한 유저 정보를 req.user에 넣어줌
6. req.user를 이용해서 로그인했는지, 했다면 정보는 무엇인지 판단 및 사용

  • 더 자세한 내용은 따로 정리해뒀으므로 링크로 대체하겠습니다.

3. passport 관련 코드

import passport from "passport";
import passportLocalConfig from "./local.js";
import db from "../models/index.js"

const { User } = db;

const passportConfig = () => {
  passport.serializeUser((user, done) => {
    done(null, user._id);
  });
  
  passport.deserializeUser(async (_id, done) => {
    try {
      const user = await User.findOne({ where: { _id } });
      done(null, user);
    } catch (error) {
      console.error("deserializeUser >> ", error);
      done(error)
    }
  });
  
  passportLocalConfig();
}

export default passportConfig;
import passport from "passport";
import { Strategy as LocalStrategy } from "passport-local";
import db from "../models/index.js";
import bcrypt from "bcrypt";

const { User } = db;

const passportLocalConfig = () => passport.use(
  new LocalStrategy(
    {
      usernameField: "id",
      passwordField: "password",
    },
    async (id, password, done) => {
      try {
        const user = await User.findOne({ where: { id } });
        if (!user) {
          return done(null, false, "존재하지 않는 아이디입니다.");
        }

        const result = await bcrypt.compare(password, user.password);
        if (result) {
          return done(null, user);
        }

        return done(null, false, "비밀번호가 틀렸습니다.");
      } catch (error) {
        console.error("passport local >> ", error);
        return done(error);
      }
    }
  )
);

export default passportLocalConfig;
import express from "express";
import passport from "passport";

import db from "../models/index.js";
import { isLoggedIn, isNotLoggedIn } from "../middleware/index.js"

const router = express.Router();
const { User, Post } = db;

router.post("/", isNotLoggedIn, (req, res, next) => {
  passport.authenticate("local", (error, user, message) => {
    // 서버측 에러 ( 조건검사 도중에 에러 )
    if (error) {
      console.error("POST /auth >> ", error);
      return res.status(500).json({ message: "서버에서 알 수 없는 에러가 발생했습니다. 잠시후에 다시 시도해주세요" });
    }

    // 클라이언트측 에러 ( 아이디 or 비밀번호 불일치 )
    if (message) {
      return res.status(403).json({ message });
    }
    
    return req.login(user, async loginError => {
      if (loginError) {
        console.error("POST /user/login loginError >> ", loginError);
        return res.status(500).json({ message: "서버에서 알 수 없는 에러가 발생했습니다. 잠시후에 다시 시도해주세요" });
      }

      // 유저와 유저와 관련된 정보까지 모아서 찾음
      const fullUser = await User.findOne({
        attributes: ["_id", "name", "createdAt"],
        where: { _id: user._id },
        include: [{ model: Post }, { model: User, as: "Followers" }, { model: User, as: "Followings" }],
      });
      
      return res.status(204).json({ message: "로그인에 성공했습니다.", user: fullUser });
    });
  })(req, res, next);
});

마무리

이미 알고 있었고, 정리해뒀던 내용이라 만드는데 많은 시간이나 큰 비용이 들지는 않았습니다.

조금 걱정되는 부분은 OAuth를 통한 로그인 전략들은 아직 구현해 보지 않았기 때문에 걱정되며 유저 테이블 구조도 변경될 것 같다고 생각됩니다.

0개의 댓글