> For the complete documentation index, see [llms.txt](https://adam-37.gitbook.io/joomadeung/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://adam-37.gitbook.io/joomadeung/node.js/node.js-express-mysql/passport.md).

# passport (일반 로그인)

1. 프론트에서 login을 할 때 email, password를 같이 보내준다.
2. routes/auth.js

`passport.authenticate('local',` 이 부분까지 실행됨.

```jsx
router.post('/login', (req, res, next) => {
  // 1. 먼저 passport가 localStrategy를 찾는다
  passport.authenticate('local', (authError, user, info) => {
    if (authError) {
      console.error(authError);
      return next(authError);
    }

    if (!user) {
      return res.redirect(`/?loginError=${info.message}`);
    }

    return req.login(user, (loginError) => {
      if (loginError) {
        console.error(loginError);
        return next(loginError);
      }

      return res.redirect('/');
    });
  })(req, res, next);
});
```

1. passport/index.js

```jsx
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(async (id, done) => {
    try {
      User.findOne({ where: { id } });
    } catch (err) {
      done(err);
    }
  });

  local(); // 이 부분이 실행된다.
  kakao();
};
```

1. passport/localStrategy.js

```jsx
const passport = require('passport');
const LocalStrategy = require('passport-local').Strategy;
const bcrypt = require('bcrypt');

const User = require('../models/user');

module.exports = () => {
  passport.use(
    new LocalStrategy(
      {
        usernameField: 'email', // req.body.email
        passwordField: 'password', // req.body.password
      },
      // done(error, user, info);
      async (email, password, done) => {
        try {
          const exUser = await User.findOne({ where: { email } });
          if (exUser) {
            const result = await bcrypt.compare(password, exUser.password);
            if (result) {
              done(null, exUser);
            } else {
              done(null, false, { message: '비밀번호가 일치하지 않습니다.' });
            }
          } else {
            done(null, false, { message: '가입되지 않은 회원입니다.' });
          }
        } catch (error) {
          console.error(error);
          done(error);
        }
      }
    )
  );
};

/**
 * done은 Passport.js에서 사용하는 콜백 함수.
 * Passport는 인증 작업을 수행할 때 사용자 정의 인증 로직을 수행하는 데 사용되는 전략(Strategies)을 구현할 수 있다.
 */
```

* **`error`**: 인증 과정에서 발생한 오류가 있는 경우 여기에 전달합니다. 정상적으로 처리되면 \*\*`null`\*\*을 전달합니다.
* **`user`**: 인증에 성공한 사용자 객체를 전달합니다. 인증에 실패한 경우 \*\*`false`\*\*를 전달합니다.
* **`info`**: 인증에 대한 추가 정보를 제공하는 객체입니다. 예를 들어, 에러 메시지나 경고 등을 전달할 수 있습니다.

1. auth.js

* localStrategy의 done 함수를 호출하면 다시 auth.js로 돌아와서 `**(authError, user, info)**`이 부분이 실행된다.
* **`req.login(user)`을 하는 순간 passport/index.js로 간다.**

```jsx
router.post('/login', (req, res, next) => {
  // 1. 먼저 passport가 localStrategy를 찾는다
  passport.authenticate('local', (authError, user, info) => {
    if (authError) {
      console.error(authError);
      return next(authError);
    }
    if (!user) {
      return res.redirect(`/?loginError=${info.message}`);
    }
    return req.login(user, (loginError) => {
      if (loginError) {
        console.error(loginError);
        return next(loginError);
      }
      return res.redirect('/');
    });
  })(req, res, next);
});
```

1. passport/index.js

* `**serializeUser`\*\* 가 실행됨
* **`req.login(user)`** 의 user가 serializeUser의 user로 들어가서 user.id만 뽑아서 done을 한다.

```jsx
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); // 세션에 user의 id만 저장
  });

  passport.deserializeUser(async (id, done) => {
    try {
      User.findOne({ where: { id } });
    } catch (err) {
      done(err);
    }
  });

  local();
  kakao();
};
```

* **serializeUser:** 사용자가 로그인에 성공하면, 사용자 객체를 세션에 저장하기 위해 **`serializeUser`** 메서드가 호출됩니다. 이 메서드는 사용자 객체를 인수로 받아 세션에 저장할 데이터(보통 사용자 ID)를 선택한 다음, **`done`** 콜백 함수를 호출하여 결과를 반환합니다. 이렇게 하면 선택한 데이터가 세션에 저장되고, 세션 ID가 클라이언트에 쿠키로 전송됨.
* **deserializeUser**: 클라이언트로부터 요청이 들어오면, Passport는 세션 ID를 사용하여 세션 데이터를 조회하고, 이를 바탕으로 사용자 객체를 복원합니다. 이때 **`deserializeUser`** 메서드가 호출되며, 세션에 저장된 데이터(사용자 ID)를 인수로 받습니다. 이 메서드는 사용자 ID를 사용하여 데이터베이스에서 사용자 객체를 조회한 다음, **`done`** 콜백 함수를 호출하여 결과를 반환합니다. 이렇게 하면 사용자 객체가 복원되고, 이후 미들웨어에서 \*\*`req.user`\*\*를 통해 사용할 수 있습니다.

1. routes/auth.js

* serialize가 done 되는 순간 `(loginError) => {}` 이 실행된다.
* 에러가 있으면 error를 표시하고 없으면 홈으로 redirect

```jsx
router.post('/login', (req, res, next) => {
  // 1. 먼저 passport가 localStrategy를 찾는다
  passport.authenticate('local', (authError, user, info) => {
    if (authError) {
      console.error(authError);
      return next(authError);
    }
    if (!user) {
      return res.redirect(`/?loginError=${info.message}`);
    }
    return req.login(user, (loginError) => {
      if (loginError) {
        console.error(loginError);
        return next(loginError);
      }
      return res.redirect('/');
    });
  })(req, res, next);
});
```

#### 정리

1. routes/auth.js - `router.post('/login’`의 `passport.authenticate('local’` 실행
2. passport/localStrategy.js - `done` 실행
3. routes/auth.js - `(authError, user, info) => {` 실행
   * 로그인 성공한 경우에는 `return req.login(user,` 의 user인자가
4. passport/index.js - `serializeUser` 실행, `user` 로 들어가서 `세션쿠키-id` 형태로 메모리에 저장 후 `done`
5. routes/index.js - `(loginError) => {` 실행,
   * 최종적으로 error가 있는지 확인 후 `redirect(’/’)` (redirect 전에 세션쿠키를 브라우저로 보내준다.)

#### 로그인 성공 후

<figure><img src="/files/KSFYYromwdlg8BdQxEOa" alt=""><figcaption></figcaption></figure>
