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

[Login & Register authentication with Node js] (7) ํŒจ์Šค์›Œ๋“œ ํ•ด์‹œํ•จ์ˆ˜ & ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ by session, bcrypt ๋ณธ๋ฌธ

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

[Login & Register authentication with Node js] (7) ํŒจ์Šค์›Œ๋“œ ํ•ด์‹œํ•จ์ˆ˜ & ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ by session, bcrypt

์ง•์ง•์•ŒํŒŒ์นด 2023. 3. 18. 01:06
728x90
๋ฐ˜์‘ํ˜•

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

=> Node.js With Passport Authentication | Full Project

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

 

 

๐Ÿฅ• ํŒจ์Šค์›Œ๋“œ ํ•ด์‹œํ•จ์ˆ˜ 

bcrypt

: hash ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ์ •๋ณด๋ฅผ ์•”ํ˜ธํ™” ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ๋Š” Node.js ํŒจํ‚ค์ง€

// bcrypt ๋ถˆ๋Ÿฌ์˜ค๊ธฐ - commonjs
const bcrypt = require("bcrypt")
// ํ•ด์‹œ ํ•จ์ˆ˜๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ ์•”ํ˜ธํ™”ํ•ด์„œ ๋ณ€์ˆ˜์— ์ €์žฅํ•˜๊ธฐ
const encrypted = bcrypt.hash("๋น„๋ฐ€๋ฒˆํ˜ธ", ํ•ด์‹œํ•จ์ˆ˜ ๋ฐ˜๋ณต ํšŸ์ˆ˜)

 

๐Ÿฅ• redirect ์™€ render ์ฐจ์ด

res.redirect(์ฃผ์†Œ)

: ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•  ์ฃผ์†Œ์™€ ํ•จ๊ป˜ ์‘๋‹ต์„ ๋ณด๋ƒ„

res.render(๋ทฐ, ๋ฐ์ดํ„ฐ)
: ํ…œํ”Œ๋ฆฟ ์—”์ง„์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ทฐ๋ฅผ ๋ Œ๋”๋ง

 

๐Ÿฅ• flash

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

 

๐Ÿฅ• Express session

: Express ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์„ธ์…˜์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฏธ๋“ค์›จ์–ด
: Server์—์„œ Client์—๊ฒŒ ์ฟ ํ‚ค๋กœ sessionID๋ฅผ ๋ฐœ๊ธ‰ํ•ด์ฃผ๊ณ ,
: ์ด ์ฟ ํ‚ค๋ฅผ ํ†ตํ•ด Server์— ์ ‘์†ํ•˜๋ฉด sessionID๊ฐ’์„ ํ™œ์šฉํ•ด ์–ด๋–ค Client์ธ์ง€ ์‹๋ณ„ํ•˜๊ณ  ๊ด€๋ จ ์ •๋ณด๋ฅผ ์ œ๊ณต

 

๐Ÿฅ• ํšŒ์›๊ฐ€์ž… ์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ hash ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ๋ณ€๊ฒฝ & ์„ธ์…˜ ๊ด€๋ฆฌํ•  sessionId ๋ฐœ๊ธ‰

 

๐Ÿง 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");

require("dotenv").config();

const app = express();

// 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,
}));

// 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");
  next();
});

// muploads ํด๋”์˜ ์‚ฌ์ง„ 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}`));

 

๐Ÿง routes/user.js

const express = require("express");
const router = express.Router();
const bcrypt = require("bcryptjs");
// 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({ emil: 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;
              console.log("hi");
              // 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));
            }))
        }
      });


  }

});

module.exports = router;

 

๐Ÿง views/login.ejs

<div class="row mt-5">
  <div class="col-md-6 m-auto">
    <div class="card card-body">
      <h1 class="text-center mb-3"><i class="fas fa-sign-in-alt"></i>Login</h1>
      <%-include('./partials/messages.ejs') %>
      <form action="/users/login" method="POST">
        <div class="form-group">
          <label for="email">Email</label>
          <input
            type="email"
            id="email"
            name="email"
            class="form-control"
            placeholder="Enter Email"
          />
        </div>
        <div class="form-group">
          <label for="password">Password</label>
          <input
            type="password"
            id="password"
            name="password"
            class="form-control"
            placeholder="Enter Password"
          />
        </div>
        <button type="submit" class="btn btn-primary btn-block">Login</button>
      </form>
      <p class="lead mt-4">No Account?<a href="/users/register">Register</a>
      </p>
    </div>
  </div>
</div>

 

๐Ÿง views/register.ejs

<div class="row mt-5">
  <div class="col-md-6 m-auto">
    <div class="card card-body">
      <h1 class="text-center mb-3"><i class="fas fa-user-plus"></i>Register</h1>
        <%-include('./partials/messages.ejs') %>
        <!-- POST๋กœ ๋ฐ›์•„์š” -->
        <form action="/users/register" method="POST">
          <div class="form-group">
            <label for="name">Name</label>
            <input 
              type="name"
              id="name" 
              name="name"
              class="form-control"
              placeholder="Enter Name"
              value="<%= typeof name != 'undefined' ? name : '' %>" />
          </div>
          <div class="form-group">
            <label for="email">Email</label>
            <input
              type="email"
              id="email"
              name="email"
              class="form-control"
              placeholder="Enter Email"
              value="<%= typeof email != 'undefined' ? email : '' %>" />
          </div>
          <div class="form-group">
            <label for="password">Password</label>
            <input
              type="password"
              id="password" 
              name="password" 
              class="form-control" 
              placeholder="Create Password"
              value="<%= typeof password != 'undefined' ? password : '' %>" />
          </div>
          <div class="form-group">
            <label for="password2">Confirm Password</label>
            <input 
              type="password" 
              id="password2"
              name="password2" 
              class="form-control"
              placeholder="Confirm Password"
              value="<%= typeof password2 != 'undefined' ? password2 : '' %>" />
          </div>
          <button type="submit" class="btn btn-primary btn-block">
            Register
          </button>
        </form>
        <p class="lead mt-4">Have An Account? <a href="/users/login">Login</a></p>
    </div>
  </div>
</div>

 

 

๐Ÿง views/partials/messages.ejs

<% if(typeof errors !="undefined" ) { %>
  <% errors.forEach(function(error) { %>
    <div class="alert alert-warning alert-dismissible fade show" role="alert">
      <%= error.msg %>
      <button type="button" class="close" data-bs-dismiss="alert" aria-label="Close"></button>
      <span aria-hidden="true">&times;</span>
    </div>
  <% }); %>
<% } %>

<% if(success_msg != "") { %>
  <div class="alert alert-warning alert-dismissible fade show" role="alert">
    <%= success_msg %>
    <button type="button" class="close" data-bs-dismiss="alert" aria-label="Close"></button>
    <span aria-hidden="true">&times;</span>
  </div>
<% } %>

<% if(error_msg != "") { %>
  <div class="alert alert-warning alert-dismissible fade show" role="alert">
    <%= error_msg %>
    <button type="button" class="close" data-bs-dismiss="alert" aria-label="Close"></button>
    <span aria-hidden="true">&times;</span>
  </div>
<% } %>

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