[BE] Passport.js๋ฅผ ํ™œ์šฉํ•œ ๊ฐ„๋‹จํ•œ ํšŒ์›์ธ์ฆ ๊ตฌํ˜„
elice/study

[BE] Passport.js๋ฅผ ํ™œ์šฉํ•œ ๊ฐ„๋‹จํ•œ ํšŒ์›์ธ์ฆ ๊ตฌํ˜„

1. ํ•„์š”ํ•œ ๋ชจ๋“ˆ ์„ค์น˜

npm install express passport passport-local express-session mongoose
  • passport, passport-local : ํšŒ์›๊ฐ€์ž…๊ณผ ๋กœ๊ทธ์ธ ์„ธ์…˜๊ด€๋ฆฌ๋ฅผ ๋„์™€์ฃผ๋Š” ๋ชจ๋“ˆ
  • express-session : ์„ธ์…˜๊ด€๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ชจ๋“ˆ

 

2. app.js ๊ธฐ๋ณธ ์„ธํŒ…

const express = require("express");
const app = express();
const passport = require("passport");
var Strategy = require("passport-local");
const session = require("express-session");
const mongoose = require("mongoose");
const User = require("./models/user");

// DB ์—ฐ๊ฒฐ
mongoose
  .connect("mongodb+srv://<username>:<password>@cluster0.p1xn6.mongodb.net/test")
  .then(async () => {
    console.log("DB ์—ฐ๊ฒฐ ์„ฑ๊ณต");
  })
  .catch((e) => {
    console.log("DB ์—ฐ๊ฒฐ ์‹คํŒจ");
  });

// POST ์š”์ฒญ ์‹œ Body๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ฝ”๋“œ
app.use(
  express.urlencoded({
    extended: true,
  })
);

// passport ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋ณธ ์„ธํŒ… ์ฝ”๋“œ๋“ค
app.use(express.json());
app.use(
  session({
    secret: "secret",
    resave: true,
    saveUninitialized: true,
  })
);
app.use(passport.initialize());
app.use(passport.session());

app.listen(3000, () => {
  console.log("3000 port listen");
});

 

3. Schema์™€ Model ์ƒ์„ฑ (models/user.js)

const mongoose = require("mongoose");

const userSchema = new mongoose.Schema({
  username: { type: String, unique: true, required: true },
  password: { type: String, required: true },
});

module.exports = mongoose.model("User", userSchema);

 

4. passport ์ธ์ฆ ์ „๋žต, serializeUser, deserializeUser ์ž‘์„ฑ

passport.use( // ์–ด๋–ค strategy๋ฅผ ์“ธ์ง€, ๊ทธ strategy๋Š” ์–ด๋–ป๊ฒŒ ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ• ์ง€ ์ •์˜
  new Strategy(function (username, password, done) {
    User.findOne({ username: username }, function (err, user) {
      //DB ์—ฐ๊ฒฐ ์‹คํŒจ ๋“ฑ์˜ ์—๋Ÿฌ
      if (err) {
        return done(err);
      }
      //username ์ž์ฒด๊ฐ€ DB์— ์—†์„ ๋•Œ
      if (!user) {
        return done(null, false, { message: "Incorrect username." });
      }
      //username์€ ๋งž์ง€๋งŒ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ฆด ๋•Œ
      if (user.password !== password) {
        // !user.validPassword(password)
        return done(null, false, { message: "Incorrect password." });
      }
      //์ธ์ฆ ์„ฑ๊ณต
      console.log("success");
      return done(null, user);
    });
  })
);

passport.serializeUser((user, done) => { // ๋กœ๊ทธ์ธ ์„ฑ๊ณต ์‹œ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ Session์— ์ €์žฅ
  done(null, user);
});

passport.deserializeUser((id, done) => { 
  // ๋กœ๊ทธ์ธ ์ •๋ณด๋ฅผ ์œ ์ง€ํ•˜๋Š” ์—ญํ• 
  // ์ธ์ฆ ํ›„ ํŽ˜์ด์ง€ ์ ‘๊ทผํ•  ๋•Œ ๋งˆ๋‹ค ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ Session์—์„œ ์ฝ์–ด์˜จ๋‹ค.
  User.findById(id, (err, user) => {
    done(err, user);
  });
});

 

5. router ์ƒ์„ฑ

5-1. index.js

const express = require("express");
const router = express.Router();

router.get("/", (req, res) => {
  console.log(req.user);
  if (req.user) { // ์ธ์ฆ๋œ ์œ ์ €๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ
    res.send(`
          <h1>ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค ${req.user.username}๋‹˜!</h1>
          <p><button><a href="/logout">๋กœ๊ทธ์•„์›ƒ</a></button></p>
      `);
  } else { // ๊ทธ ์™ธ
    res.redirect("/login");
  }
});

module.exports = router;

5-2. join.js

const express = require("express");
const User = require("../models/user");
const router = express.Router();
const bcrypt = require("bcryptjs");

router.get("/", (req, res) => {
  res.send(`
        <h1>ํšŒ์›๊ฐ€์ž…</h1>
        <form action="/join" method="POST">
            <div>
                <label>Username:</label>
                <input type="text" name="username"/>
            </div>
            <div>
                <label>Password:</label>
                <input type="password" name="password"/>
            </div>
            <div>
                <input type="submit" value="ํšŒ์›๊ฐ€์ž…"/>
            </div>
        </form>
    `);
});

router.post("/", async (req, res) => {
  const { username, password } = req.body;

  try {
    const findData = await User.findOne({ username });
    if (findData) { // ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ์œ ์ €์ธ ๊ฒฝ์šฐ
      return res.status(400).json({ errors: [{ msg: "User already exists" }] });
    }

    newUser = new User({
      username,
      password,
    });

    await newUser.save(); // DB์— ์ €์žฅ

    res.send(`
      <h1>ํšŒ์›๊ฐ€์ž… ์„ฑ๊ณต!</h1>
      <button><a href='/login'>๋กœ๊ทธ์ธ ํ•˜๋Ÿฌ๊ฐ€๊ธฐ</a></button>
    `);
  } catch (err) { // ์„œ๋ฒ„ ์—๋Ÿฌ
    console.error(err.message);
    res.status(500).send("Server Error");
  }
});

module.exports = router;

5-3. login.js

const express = require("express");
const router = express.Router();
const passport = require("passport");
const bcrypt = require("bcryptjs");

router.get("/", (req, res) => {
  res.send(`
        <h1>๋กœ๊ทธ์ธ</h1>
        <form action="/login" method="POST">
            <div>
                <label>Username:</label>
                <input type="text" name="username"/>
            </div>
            <div>
                <label>Password:</label>
                <input type="password" name="password"/>
            </div>
            <br />
            <div>
                <input type="submit" value="๋กœ๊ทธ์ธ"/>
            </div>
        </form>
      <button><a href='/join'>ํšŒ์›๊ฐ€์ž…</a></button>
    `);
});

router.post( // ์•ž์„œ ์ž‘์„ฑํ•œ strategy๋ฅผ ํ†ตํ•ด ์ธ์ฆ์˜ ์„ฑ๊ณต/์‹คํŒจ ์—ฌ๋ถ€์— ๋”ฐ๋ผ redirectํ•  ๊ฒฝ๋กœ ์ง€์ •
  "/",
  passport.authenticate("local", {
    failureRedirect: "/login",
    failureMessage: true,
  }),
  function (req, res) {
    res.redirect("/");
  }
);

module.exports = router;

5-4. logout.js

const express = require("express");
const router = express.Router();
const session = require("express-session");

router.get("/", (req, res) => {
  req.logout();
  req.session.destroy(); // ๋กœ๊ทธ์•„์›ƒ ํ›„ ์„ธ์…˜ ์‚ญ์ œ
  res.redirect("/");
});

module.exports = router;

 

6. Router ์—ฐ๊ฒฐ

const express = require("express");
const app = express();
const passport = require("passport");
var Strategy = require("passport-local");
const session = require("express-session");
const mongoose = require("mongoose");
const User = require("./models/user");

const indexRouter = require("./routes/index");
const loginRouter = require("./routes/login");
const joinRouter = require("./routes/join");
const logoutRouter = require("./routes/logout");

mongoose
  .connect("mongodb+srv://admin:1234@cluster0.p1xn6.mongodb.net/test")
  .then(async () => {
    console.log("DB ์—ฐ๊ฒฐ ์„ฑ๊ณต");
  })
  .catch((e) => {
    console.log("DB ์—ฐ๊ฒฐ ์‹คํŒจ");
  });

app.use(
  express.urlencoded({
    extended: true,
  })
);
app.use(express.json());
app.use(
  session({
    secret: "secret",
    resave: true,
    saveUninitialized: true,
  })
);
app.use(passport.initialize());
app.use(passport.session());

app.use("/", indexRouter);
app.use("/login", loginRouter);
app.use("/join", joinRouter);
app.use("/logout", logoutRouter);

passport.use(
  new Strategy(function (username, password, done) {
    User.findOne({ username: username }, function (err, user) {
      //DB ์—ฐ๊ฒฐ ์‹คํŒจ ๋“ฑ์˜ ์—๋Ÿฌ
      if (err) {
        return done(err);
      }
      //username ์ž์ฒด๊ฐ€ DB์— ์—†์„ ๋•Œ
      if (!user) {
        return done(null, false, { message: "Incorrect username." });
      }
      //username์€ ๋งž์ง€๋งŒ ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ฆด ๋•Œ
      if (user.password !== password) {
        // !user.validPassword(password)
        return done(null, false, { message: "Incorrect password." });
      }
      //์ธ์ฆ ์„ฑ๊ณต
      console.log("success");
      return done(null, user);
    });
  })
);

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

passport.deserializeUser((id, done) => {
  User.findById(id, (err, user) => {
    done(err, user);
  });
});

app.listen(3000, () => {
  console.log("3000 port listen");
});

 

7. ๋™์ž‘ ํ™•์ธ

7-1. ์ดˆ๊ธฐ ํ™”๋ฉด

์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ ํ•˜์ง€ ์•Š์•˜์œผ๋ฏ€๋กœ, '/login' ํŽ˜์ด์ง€๋กœ redirect ๋œ๋‹ค.

7-2. ํšŒ์›๊ฐ€์ž…

ํšŒ์›๊ฐ€์ž… ํ›„์˜ ํ™”๋ฉด๊ณผ DB

7-3. ๋กœ๊ทธ์ธ

if (req.user) ์กฐ๊ฑด์— ์˜ํ•ด ์ธ์ฆ๋œ ์œ ์ €์˜ ํ™”๋ฉด ์ƒ์„ฑ

7-4. ๋กœ๊ทธ์•„์›ƒ

 

 

 

'elice > study' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[CS] AJAX  (0) 2022.02.28
[BE] REST API  (0) 2022.02.21
[BE] ๋ผ์šฐํŒ…(Routing)  (0) 2022.02.14
[CS] ์‹œ๋งจํ‹ฑ ๋งˆํฌ์—…  (0) 2022.02.14
[CS] script, script async, script defer  (0) 2022.02.14