๐ ๊ณต๋ถํ๋ ์ง์ง์ํ์นด๋ ์ฒ์์ด์ง?
[Login & Register authentication with Node js] (7) ํจ์ค์๋ ํด์ํจ์ & ๋ฉ์์ง ์ถ๋ ฅ by session, bcrypt ๋ณธ๋ฌธ
[Login & Register authentication with Node js] (7) ํจ์ค์๋ ํด์ํจ์ & ๋ฉ์์ง ์ถ๋ ฅ by session, bcrypt
์ง์ง์ํ์นด 2023. 3. 18. 01:06<๋ณธ ๋ธ๋ก๊ทธ๋ 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">×</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">×</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">×</span>
</div>
<% } %>