๐Ÿ˜Ž ๊ณต๋ถ€ํ•˜๋Š” ์ง•์ง•์•ŒํŒŒ์นด๋Š” ์ฒ˜์Œ์ด์ง€?

[Login & Register authentication with Node js] (8) ๋กœ๊ทธ์ธ ์‹œ auth ์ธ์ฆ ํ›„, dashboard ๋„์šฐ๊ธฐ by passport ๋ณธ๋ฌธ

๐Ÿ‘ฉ‍๐Ÿ’ป ๋ฐฑ์—”๋“œ(Back-End)/Node js

[Login & Register authentication with Node js] (8) ๋กœ๊ทธ์ธ ์‹œ auth ์ธ์ฆ ํ›„, dashboard ๋„์šฐ๊ธฐ by passport

์ง•์ง•์•ŒํŒŒ์นด 2023. 3. 20. 00:48
728x90
๋ฐ˜์‘ํ˜•

<๋ณธ ๋ธ”๋กœ๊ทธ๋Š” Traversy Media ์˜ ์œ ํŠœ๋ธŒ๋ฅผ ์ฐธ๊ณ ํ•ด์„œ ๊ณต๋ถ€ํ•˜๋ฉฐ ์ž‘์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค :-)>

=> Node.js With Passport Authentication | Full Project

=> authentication app with login, register and access control using Node.js, Express, Passport, Mongoose

 

 

 

๐Ÿฅ• ๋กœ๊ทธ์ธ์„ ๋„์™€์ฃผ๋Š” passpoart

์ด๋ฆ„์ฒ˜๋Ÿผ ์ž์‹ ์˜ ์›น์‚ฌ์ดํŠธ์— ๋ฐฉ๋ฌธํ•  ๋•Œ ์—ฌ๊ถŒ๊ฐ™์€ ์—ญํ• 

๋กœ๊ทธ์ธ์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์คŒ

 

  // login์ด ์ตœ์ดˆ๋กœ ์„ฑ๊ณตํ–ˆ์„ ๋•Œ๋งŒ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜
  // done(null, user.id)๋กœ ์„ธ์…˜์„ ์ดˆ๊ธฐํ™”
  passport.serializeUser(function (user, cb) {
    process.nextTick(function () {
      return cb(null, user);
    });
  });

  // ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜
  // done(null, id)๋กœ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๊ฐ request์˜ user ๋ณ€์ˆ˜์— ๋„ฃ์Œ  
  passport.deserializeUser(function (user, cb) {
    process.nextTick(function () {
      return cb(null, user);
    });
  });

serializeUser : function(user, cb) ์„ ์ด์šฉํ•ด์„œ session์— ์ €์žฅํ•  ์ •๋ณด cb(null, user) ๋ฅผ ๋„˜๊น€
(์›๋ž˜ ์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ํฌ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋งŽ์ด ์†Œ๋ชจํ•ด์„œ, ์‚ฌ์šฉ์ž id์™€ ๊ฐ™์€ ํ‚ค ์ •๋ณด๋งŒ ์ €์žฅํ•˜๋Š”๋ฐ ๋’ค์—์„œ name์ด ํ•„์š”ํ•œ๋ฐ id๋งŒ ๋„˜์–ด์™€์„œ ์ฉ” ์ˆ˜์—†์ด ์‚ฌ์šฉ์ž ์ •๋ณด ๋ชจ๋‘ ์ €์žฅํ•จ)
LocalStrategy : ๊ฐ์ฒด์˜ ์ธ์ฆํ•จ์ˆ˜์—์„œ cb(null, user) ์— ์˜ํ•ด ๋ฆฌํ„ด๋œ ๊ฐ’์ด ๋„˜์–ด ์˜ด
deserializeUser : node.js์˜ ๋ชจ๋“  ํŽ˜์ด์ง€์— ์ ‘๊ทผํ• ๋•Œ, ๋กœ๊ทธ์ธ์ด ๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ ๋ชจ๋“  ์‚ฌ์šฉ์ž ํŽ˜์ด์ง€๋ฅผ ์ ‘๊ทผํ•  ๊ฒฝ์šฐ, deserilizeUser๊ฐ€ ๋ฐœ์ƒ
session์— ์ €์žฅ๋œ ๊ฐ’์„ ์ด์šฉํ•ด์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ์ฐพ์€ ํ›„ HTTP request์˜ ๋ฆฌํ„ด
์‹ค์ œ ์„œ๋ฒ„๋กœ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ๋งˆ๋‹ค ์„ธ์…˜ ์ •๋ณด(serializeUser์—์„œ ์ €์žฅ๋จ)๋ฅผ ์‹ค์ œ DB์˜ ๋ฐ์ดํ„ฐ์™€ ๋น„๊ต

 

๐Ÿง middlewares/passport.js

// ์ธ์ฆ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ด์ฃผ๋Š” Node.js์˜ ์ธ์ฆ ๋ฏธ๋“ค์›จ์–ด

const LocalStrategy = require("passport-local").Strategy;
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");

// Load user model
const User = require("../models/User");

module.exports = (passport) => {
  passport.use(
    new LocalStrategy({ usernameField: "email" }, (email, password, done) => {
      // Match User
      User.findOne({ email: email })
        .then(user => {
          // user ๊ฐ€ ์—†๋‹ค๋ฉด done
          if (!user) {
            return done(null, false, { message: "That email is not registered!" });
          }
          // Match password (๊ธฐ์กด ๋น„๋ฐ€๋ฒˆํ˜ธ์™€ ์ž…๋ ฅํ•œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ฒดํฌ)
          bcrypt.compare(password, user.password, (err, isMatch) => {
            if (err) throw err;

            if (isMatch) {
              return done(null, user);
            } else {
              return done(null, false, { message: "Password is incorrect!" });
            }
          });
        })
        .catch(err => console.log(err));
    })
  );

  // login์ด ์ตœ์ดˆ๋กœ ์„ฑ๊ณตํ–ˆ์„ ๋•Œ๋งŒ ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜
  // done(null, user.id)๋กœ ์„ธ์…˜์„ ์ดˆ๊ธฐํ™”
  passport.serializeUser(function (user, cb) {
    process.nextTick(function () {
      return cb(null, user);
    });
  });

  // ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋ฐฉ๋ฌธํ•  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๋Š” ํ•จ์ˆ˜
  // done(null, id)๋กœ ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ๊ฐ request์˜ user ๋ณ€์ˆ˜์— ๋„ฃ์Œ  
  passport.deserializeUser(function (user, cb) {
    process.nextTick(function () {
      return cb(null, user);
    });
  });
}

 

๐Ÿง middlewares/auth.js

module.exports = {
  ensureAuthenticated: (req, res, next) => {
    if (req.isAuthenticated()) {
      return next();
    }
    req.flash("error_msg", "Plz, log in to view this resource!");
    res.redirect("/users/login");
  }
}

 

๐Ÿง routes/index.js

const express = require("express");
const router = express.Router();
const { ensureAuthenticated } = require("../middlewares/auth");

// Main page
router.get("/", (req, res) => {
  // rednering ํ•  ๋•Œ view์˜ ํŒŒ์ผ ์ด๋ฆ„ ์จ์•ผ๋จ
  res.render("welcome");
});

// dashboard
router.get("/dashboard", ensureAuthenticated, (req, res) => {
  // rendering ํ•  ๋•Œ view์˜ ํŒŒ์ผ ์ด๋ฆ„ ์จ์•ผ๋จ
  res.render("dashboard", {
    name : req.user.name
  });
});

module.exports = router;

 

๐Ÿง routes/user.js

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

// Login Page
router.get("/login", (req, res) => {
  res.render("login");
});

// Register Page
router.get("/register", (req, res) => {
  res.render("register");
});

// Register Handle
router.post('/register', (req, res) => {
  const { name, email, password, password2 } = req.body;
  let errors = [];

  if (!name || !email || !password || !password2) {
    errors.push({ msg: 'Please enter all fields' });
  }

  if (password != password2) {
    errors.push({ msg: 'Passwords do not match' });
  }

  if (password.length < 6) {
    errors.push({ msg: 'Password must be at least 6 characters' });
  }

  if (errors.length > 0) {
    res.render('register', {
      errors,
      name,
      email,
      password,
      password2
    });
  } else {
    // validation pass
    User.findOne({ email: email })
      .then(user => {
        // email์„ ์ฐพ์•˜๋Š”๋ฐ ๋งŒ์•ฝ์— user๊ฐ€ ์žˆ๋‹ค๋ฉด
        if (user) {
          errors.push({ msg: "Email is already registered!" });
          res.render('register', {
            errors,
            name,
            email,
            password,
            password2
          });
        } else {
          // ํšŒ์›๊ฐ€์ž…๋œ email์ด ์—†๋‹ค๋ฉด
          const newUser = new User({
            name,
            email,
            password
          });

          console.log(newUser);

          // hash password
          bcrypt.genSalt(10, (err, salt) =>
            bcrypt.hash(newUser.password, salt, (err, hash) => {
              if (err) throw err;
              // Set password to hased
              newUser.password = hash;
              // save user
              newUser.save()
                .then(user => {
                  req.flash("success_msg", "You are now registered and can log in!!");
                  res.redirect('/users/login');
                })
                .catch(err => console.log(err));
            }))
        }
      });
  }
});

// Login handle
router.post("/login", (req, res, next) => {
  passport.authenticate("local", {
    // ์„ฑ๊ณตํ•˜๋ฉด ๋ฉ”์ธ์œผ๋กœ
    successRedirect : "/dashboard",
    // ์‹คํŒจํ•˜๋ฉด ๋‹ค์‹œ ๋กœ๊ทธ์ธ
    failureRedirect : "/users/login",
    failureFlash : true
  }) (req, res, next);
});

// Logout handle
router.get('/logout', (req, res, next) => {
  req.logOut(err => {
    if (err) {
      return next(err);
    } else {
      console.log('๋กœ๊ทธ์•„์›ƒ๋จ.');
      req.flash("success-msg", "You are logged out!");
      res.redirect("/users/login");
    }
  });
});

module.exports = router;

 

๐Ÿง app.js

const express = require("express");
const expressLayouts = require("express-ejs-layouts");
const mongoose = require("mongoose");
const flash = require("connect-flash");
const session = require("express-session");
const passport = require("passport");
const app = express();

require("dotenv").config();
require("./middlewares/passport")(passport);

// DB config
const db = process.env.MONGODB_URI;

// connect to Mongo
mongoose.connect(db, {
  useNewUrlParser: true,    // useNewUrlParser : ์—๋Ÿฌ ๋ฐฉ์ง€
  useUnifiedTopology: true
})
  .then(() => console.log("๐Ÿ’šMongoDB Connected..."))
  .catch(err => console.log(err));

// ejs ๋ฏธ๋“ค์›จ์–ด
app.use(expressLayouts);
// express ์˜ view ์—”์ง„์„ ejs ๋กœ ์„ธํŒ…
app.set("view engine", "ejs");

// Bodyparser
// express์„œ๋ฒ„๋กœ POST์š”์ฒญ์„ ํ•  ๋•Œ inputํƒœ๊ทธ์˜ value๋ฅผ ์ „๋‹ฌ
// URL-encoded ํ˜•์‹์˜ ๋ฌธ์ž์—ด๋กœ ๋„˜์–ด์˜ค๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ์ฒด๋กœ์˜ ๋ณ€ํ™˜ ํ•„์š”
app.use(express.urlencoded({ extended: false }));

// Express session
// Express ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์„ธ์…˜์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฏธ๋“ค์›จ์–ด
// Server์—์„œ Client์—๊ฒŒ ์ฟ ํ‚ค๋กœ sessionID๋ฅผ ๋ฐœ๊ธ‰ํ•ด์ฃผ๊ณ ,
// ์ด ์ฟ ํ‚ค๋ฅผ ํ†ตํ•ด Server์— ์ ‘์†ํ•˜๋ฉด sessionID๊ฐ’์„ ํ™œ์šฉํ•ด ์–ด๋–ค Client์ธ์ง€ ์‹๋ณ„ํ•˜๊ณ  ๊ด€๋ จ ์ •๋ณด๋ฅผ ์ œ๊ณต
app.use(session({
  secret: 'secret',
  resave: true,
  saveUninitialized: true,
}));

// passport ์ดˆ๊ธฐํ™” ๋ฐ session ์—ฐ๊ฒฐ ๋ฏธ๋“ค์›จ์–ด
app.use(passport.authenticate('session'));
app.use(passport.initialize());
app.use(passport.session());

// Connect flash
// ํ•œ ๋ฒˆ ์ถœ๋ ฅ๋˜๊ณ  ์‚ฌ๋ผ์ง€๋Š” ๋ฉ”์‹œ์ง€
// session ๋ณด๋‹ค ์•„๋ž˜์ชฝ์—์„œ ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์„ค์น˜
// flash ๋ฉ”์‹œ์ง€๋Š” Queue์ฒ˜๋Ÿผ ๋ฐ์ดํ„ฐ๋ฅผ ๊บผ๋‚ด๋Š” ์ฆ‰์‹œ, session์—์„œ ์‚ญ์ œ
app.use(flash());

// Global Vars
app.use((req, res, next) => {
  // res.locals : ๋ทฐ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๊ธฐ๋ณธ ์ฝ˜ํ…์ŠคํŠธ๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฐ์ฒด
  res.locals.success_msg = req.flash("success_msg");
  res.locals.error_msg = req.flash("error_msg");
  res.locals.error = req.flash("error");
  next();
});

// uploads ํด๋”์˜ ์‚ฌ์ง„ html์— ๋ณด์ด๊ฒŒ ํ•˜๊ธฐg
app.use(express.static('public'));

// Routes
app.use("/", require("./routes/index"));
app.use("/users", require("./routes/user"));

const PORT = process.env.PORT || 8000;

app.listen(PORT, console.log(`๐Ÿš€Server started on port http://localhost:${PORT}`));

 

๐Ÿง views/dashboard.ejs

<h1 class="mt-4">Dashboard</h1>
<p class="lead mb-3">Welcome User! <%= name %></p>
<a href="/users/logout" class="btn btn-secondary">Logout</a>

 

๋กœ๊ทธ์ธ ์‹œ์ž‘~
๋กœ๊ทธ์ธ ํŽ˜์ด์ง€์™€ ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€ ^^ 
๋น„๋ฐ€๋ฒˆํ˜ธ ์ด๋ฉ”์ผ ํ‹€๋ฆผ~~~~ ์ด๋ฉ”์ผ์€ ๋“ฑ๋ก๋˜์ง€ ์•Š์Œ~~ ํšŒ์›๊ฐ€์ž… ํ•˜์…ˆ 
hello ๋‹˜ ํ™˜์˜ํ•˜์˜ค~~~ logout ๋ˆ„๋ฅด๋ฉด login์œผ๋กœ ๋„˜์–ด๊ฐ

 

 

728x90
๋ฐ˜์‘ํ˜•
Comments