사용자 회원가입 시 이메일과 패스워드를 입력받아 DB에 저장할 때 패스워드를 plain text로 저장하지 않고 변형하여 저장한다.
사용자 로그인 시 입력받은 plain 패스워드와 DB에 변형되어 저장된 패스워드를 비교하여 로그인 결과를 반환한다.

프로젝트 구조
.
├── app.js
├── package.json
├── public
│ ├── css
│ └── favicon.ico
└── views
├── home.ejs
├── login.ejs
├── partials
├── register.ejs
├── secrets.ejs
└── submit.ejs
login.ejs
<%- include('partials/header') %>
<!--생략-->
<!-- Makes POST request to /login route -->
<form action="/login" method="POST">
<div class="form-group">
<label for="email">Email</label>
<input type="email" class="form-control" name="username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" class="form-control" name="password">
</div>
<button type="submit" class="btn btn-dark">Login</button>
</form>
<!--생략-->
<%- include('partials/footer') %>
app.js
require('dotenv').config();
const express = require('express');
const bodyParser = require('body-parser');
const ejs = require('ejs');
const mongoose = require('mongoose');
const app = express();
app.use(express.static('public'));
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));
mongoose.connect('mongodb://localhost:27017/userDB', { useNewUrlParser: true });
const userSchema = new mongoose.Schema({
email: String,
password: String,
});
const User = mongoose.model('User', userSchema);
app.get('/', (req, res) => {
res.render('home');
});
app.get('/login', (req, res) => {
res.render('login');
});
app.get('/register', (req, res) => {
res.render('register');
});
app.post('/register', (req, res) => {
const newUser = new User({
email: req.body.username,
password: req.body.password
});
newUser.save((err) => {
if (err) {
console.log(err);
} else {
res.render('secrets');
}
});
});
app.post('/login', (req, res) => {
const username = req.body.username;
const password = req.body.password;
User.findOne({ email: username }, function (err, foundUser) {
if (err) {
console.log(err);
} else {
if (foundUser.password == password) {
res.render('secrets');
}
}
});
});
app.listen(3000, () => {
console.log('Server running on 3000');
});
위의 코드들은 DB에 사용자의 password를 plain text로 저장하여 보안성이 떨어진다. 따라서 패스워드를 저장할 때는 다양한 암호화를 수행한 후 저장하는 것이 바람직하다.
bcrypt 패키지 설치
$ npm i bcrypt
app.js에 추가
const bcrypt = require('bcrypt');
const saltRounds = 10;
bcrypt.hash(plaintextPassword, saltRounds, function(err, hash) {
// DB에 패스워드 저장하는 코드
});
app.js
app.post('/register', (req, res) => {
bcrypt.hash(req.body.password, saltRounds, function (err, hash) {
const newUser = new User({
email: req.body.username,
password: hash,
});
newUser.save((err) => {
if (err) {
console.log(err);
} else {
// 시크릿 페이지로 이동
res.render('secrets');
}
});
});
});
// DB에서 패스워드 로드
bcrypt.compare(myPlaintextPassword, hash, function(err, result) {
// result == true
});
bcrypt.compare(someOtherPlaintextPassword, hash, function(err, result) {
// result == false
});
compare(data, encrypted, cb)
app.post('/login', (req, res) => {
const username = req.body.username;
const password = req.body.password;
// DB에서 email 속성이 username인 문서 검색
// 검색결과를 콜백으로 확인한다.
User.findOne({ email: username }, function (err, foundUser) {
if (err) {
console.log(err);
} else {
// 유저가 DB에 등록되어 있을 때
if (foundUser) {
// 입력받은 패스워드와 DB에 암호화되어 저장된 패스워드를 비교
bcrypt.compare(password, foundUser.password, function (err, result) {
if (result == true) {
res.render('secrets');
}
});
}
}
});
});