Home 로그인 페이지 만들기 - 08 (passport)
Post
X

로그인 페이지 만들기 - 08 (passport)

passport 모듈을 활용해 id와 passport를 이용한 기본적인 인증 방식을 구현해보자.


Passport 모듈

추후에 SSO를 사용하여 사용자 로그인을 구현할 예정이므로 Passport 모듈을 이용해 로그인 기능을 구현해보겠습니다.


모듈 설치 및 연결

  • 설치
    1
    
    npm i passport passport-local
    

app.js 파일에 passport 모듈을 연결해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...

import sessionMiddleware from "./src/config/session.js";
import passport from "passport";
import passportConfig from "./src/config/passport/index.js";


const app = express();

const __dirname = path.resolve();


...


// req 객체에 passport 설정을 입력
app.use(passport.initialize());
passportConfig();

app.use(sessionMiddleware);
app.use(passport.session()); // req.session 객체에 passport정보를 추가 저장
// express-session에 의존하므로 뒤에 작성합니다.
// passport.session()이 실행되면, 세션쿠키 정보를 바탕으로 해서 passport/index.js의 deserializeUser()가 실행됩니다.

...



config/passport 작성

먼저 config/passport/index.jsserializeUserdeserializeUser를 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// config/passport/index.js
import passport from "passport";
import local from "./localStrategy.js";

import UserStorage from "../../models/model_user.js";

export default () => {
  passport.serializeUser((req, user, done) => {
    done(null, user.id);
    // 자원낭비를 줄이기 위해 id만 저장합니다.
  });

  passport.deserializeUser(async (req, id, done) => {
    try {
      const user = await UserStorage.getUserInfo(id);

      done(null, user);
    } catch (err) {
      done(err);
    }
  });

  local();
};

다음 localStrategy.js 파일에 id + password로 인증하는 전략을 작성합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// config/passport/localStrategy.js
import passport from "passport";
import { Strategy as LocalStrategy } from "passport-local";
import { userPasswordVerify } from "../utils/crypto_util.js";

import UserStorage from "../models/model_user.js";

export default () => {
  passport.use(
    "local",
    new LocalStrategy(
      // passport는 기본적으로 username와 password를 req에서 가져와 비교한다.
      // 그 설정을 바꾸기 위해서 new LocalStrategy의 첫번째 인자로
      //  usernameField: '아이디로 원하는 이름',
      //  passwordField: '비밀번호로 원하는 이름'
      {
        usernameField: "id",
        passwordField: "password",
        // session: true, // 세션에 저장 여부
        // passReqToCallback: false,
      },
      async (id, password, done) => {
        try {
          let user = await UserStorage.getUserInfo(id);

          if (!user) {
            return done(null, false, {
              success: false,
              msg: "가입되지 않은 회원입니다.",
            });
          }

          let checkedPassword = await userPasswordVerify(
            password,
            user.password
          );

          if (checkedPassword) {
            return done(null, user);
          }

          done(null, false, {
            success: false,
            msg: "비밀번호가 틀렸습니다.",
          });
        } catch (err) {
          done(err);
        }
      }
    )
  );
};

Route 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import express from "express";
import ctrl from "../controllers/controller_user.js";
import validator_user from "../middleware/validator_user.js";

const Router = express.Router();

Router.get("/info", ctrl.output.info);
Router.get("/login", ctrl.output.login);
Router.get("/register", ctrl.output.register);
Router.get("/logout", ctrl.process.logout);

Router.post("/login", validator_user.login, ctrl.process.login);
Router.post("/register", validator_user.register, ctrl.process.register);

export default Router;

Controller 파일 수정

기존에 Controller에서 if 문과 response 객체를 활용해 인증했던 작업을 Passport 모듈을 이용해서 작성합니다.

Controller가 조금 더 간결한 코드로 작성된 것을 확인할 수 있습니다.
(크게 차이는 없지만 추가로 카카오, 네이버 등으로 로그인 기능을 확장이 쉬운 장점이 있습니다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import passport from "passport";
import {
  createPasswordAndSalt,
} from "../middleware/crypto.js";
import UserStorage from "../models/model_user.js";

const output = {
  info: (req, res) => {
    res.render("user/info", {
      // 저장된 세션으로 로그인 된 상태인지 확인
      name: req.session.isLogined ? req.session.name : null,
    });
  },

  login: ...,

  register: ...,
};

const process = {
  login: (req, res, next) => {
    passport.authenticate("local", (err, user, response) => {
      if (err) return next(err);

      if (!user) return res.json(response);

      return req.login(user, { session: false }, async (loginErr) => {
        if (loginErr) return next(loginErr);

        // 로그인 성공 했을 때
        req.session.isLogined = true;
        req.session.name = user.name;

        return res.json({ success: true });
      });
    })(req, res, next); // 미들웨어 내의 미들웨어에는 (req, res, next)를 붙입니다.
  },

  register: ...,

  logout: ...,
};

export default { output, process };

참조

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.