Skip to content

Passport로 OAuth 구현하기

Sangwoo Park edited this page Jun 2, 2022 · 1 revision

본 프로젝트에서는 로컬과 소셜 로그인을 모두 기획했는데 어떤 방식으로 소셜 로그인을 구현할지 고민했습니다. 각 기업에서 공개한 API를 이용해 직접 구현하는 방법과 Passport를 사용하는 방법을 모두 고려했는데, 구현의 복잡도를 낮추고 시간을 절약하기 위해 Passport를 사용하자고 의견이 모였습니다.

Passport란?

Passport는 Node.js에서 사용되는 인증 미들웨어입니다. Passport는 여러 인증 방법을 Strategy라는 이름으로 제공합니다. Strategy는 모듈 형태로 제공되어 간단하게 OAuth 로그인을 구현할 수 있습니다.

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

먼저 Express에서 Passport를 사용하고, Passport로 세션 기반 인증을 구현하기 위해 필요한 미들웨어를 불러옵니다.

인증절차

1. Authenticate

router.post(
  '/sign-in_process',
  passport.authenticate('local', { failureRedirect: '/auth/sign-in' }),
  (req, res) => {
    req.session.save(() => {
      res.redirect('/');
    });
  }
);

passport.authenticate/sign-in_process에서 사용자가 입력한 데이터를 어떤 Strategy로 검증할지 결정하고, 로그인 이후의 추가적인 처리나 리다이렉션을 담당합니다. 여기에서는 리다이렉션 전에 사용자의 식별자가 담긴 세션을 DB에 먼저 저장해야 하기 때문에 리다이렉션을 콜백함수로 넣었습니다.

2. Local Strategy

passport.use(
  new LocalStrategy(
    {
      usernameField: 'email',
      passwordField: 'pwd'
    },
    (email, password, done) => {
      const sql = 'SELECT * FROM user WHERE email=?';
      db.query(sql, [email], (err, results) => {
        const user = results[0];
        if (err) {
          return done(err);
        }
        if (!user) {
          return done(null, false, { message: 'Incorrect email' });
        }
        if (password !== user.password) {
          return done(null, false, { message: 'Incorrect password' });
        }
        return done(null, user);
      });
    }
  )
);

LocalStrategy는 사용자가 입력한 데이터를 가져오고, 검증에 성공하면 그 데이터를 user에 담아 반환합니다.

3. Serialize

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

passport.authenticateLocalStrategy를 통해 user에 사용자가 입력한 정보가 담기면, passport.serializeUser는 사용자 식별자인 user.id를 세션에 저장합니다. 로그인에 성공했을 때만 호출되어 세션에 기록을 남기게 됩니다.

4. Deserialize

passport.deserializeUser((id, done) => {
  const sql = 'SELECT * FROM user WHERE id=?';
  db.query(sql, [id], (err, results) => {
    const user = results[0];
    if (!user) {
      return done(err, false);
    }
    return done(null, user);
  });
});

passport.deserializeUser는 세션에 저장된 사용자 식별자를 id로 받아 DB에서 추가적인 사용자 정보를 찾은 후, 해당 정보를 req.user 의 값으로 다른 페이지에 전달합니다. 로그인이 성공한 상태에서 페이지에 방문할 때마다 로그인한 사용자인지 조회하는 역할을 합니다.

보완점

  • DB에 저장되는 비밀번호를 암호화할 필요가 있습니다.
  • 페이지 접근마다 DB SELECT가 발생하기 때문에 성능 저하가 올 수 있습니다.