Express ๋ฏธ๋ค์จ์ด ์ ๋๋ก ์ฌ์ฉํ๊ธฐ + ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ
๐งฉ ๋ชฉ์
express์ ํน์ง์ ๋ํด์๋ Node ๊ฐ๋ฐ์๋ผ๋ฉด ์์์ผ ํ ๊ธฐ๋ณธ ์ง์ ํฌ์คํ ์ ํตํด ์ ๋ฆฌํ์ผ๋ ์ด๋ฒ์๋ express generator๋ก ์์ฑ๋๋ ์ฌ๋ฌ ๋ฏธ๋ค์จ์ด์ ๋ก๊ทธ์ธ ํ๋ก๊ทธ๋จ ๊ตฌํ์ ์ฌ์ฉ๋ ๋ฏธ๋ค์จ์ด๋ฅผ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํ๋ค.
๐ฝ๏ธ ํ๋ก์ ํธ ๊นํ ๋ ํฌ์งํ ๋ฆฌ
[์ฐ์ํํ ํฌ์บ ํ] ๋ฐฐ๋ฏผ์ํ ํ์๊ฐ์ /๋ก๊ทธ์ธ ๊ตฌํ ํ๋ก์ ํธ
๐ญ Express ์ฃผ์ ๋ฏธ๋ค์จ์ด
pug
Express๋ ๋ฐํ์์ ํ ํ๋ฆฟ ์์ง์ ์ด์ฉํด์ ์ฌ๋ฌ ๋ณ์๊ฐ ์๋ staticํ ํ ํ๋ฆฟ ํ์ผ์ ์ค์ ๊ฐ์ ๋ฃ์ด html ํ์ผ์ ์์ฑํ๋ค.
Pug๋ ๊ฐ์ฅ ๋ํ์ ์ธ ํ ํ๋ฆฟ์์ง์ผ๋ก ํ ํ๋ฆฟ์ด ์๋ ๋๋ ํ ๋ฆฌ๋ฅผ views์ ์ ํด์ฃผ๊ณ view engine์ผ๋ก pug๋ก ์ค์ ํด์ฃผ๋ฉด ์ฌ์ฉํ ์ ์๋ค.
app.js์ view engine ์ข ๋ฅ์ template directory๋ฅผ ์ ํด์ฃผ๊ณ
app.set('views', './views');
app.set('view engine', 'pug');
๋ค์๊ณผ ๊ฐ์ด index.pug ๋ฅผ ๋ง๋ค์ด ์ฃผ๊ณ title์ ๋ํ ๋ณ์๊ฐ์ ์ ๋ฌ๋ฐ๋ template์ ์ค์ ํ๊ณ
extends layout
block content
h1= title
p Welcome to #{title}
router.js ์์ res.render ํจ์๋ฅผ ํตํด ์ฌ์ฉํ template๊ณผ ๋ณ์ ๊ฐ์ ์ ๋ฌํด์ฃผ๋ฉด
router.get('/', function (req, res, next) {
res.render('index', { title: 'Express' });
});
template์ ๋ณ์ ๊ฐ์ ๋ฃ์ด์ ํด๋นํ๋ ํ์ด์ง๋ฅผ ์ ์ ์๊ฒ ์ ๋ฌ๋๋ค.
morgan
morgan์ ์ด๋ฆ์์ ๋ฐ๋ก ์ ์ ์์ง๋ง request๋ฅผ logging์ ํด์ฃผ๋ ์์ฃผ ์ ์ฉํ ๋ฏธ๋ค์จ์ด์ด๋ค.
var logger = require('morgan');
// ยทยทยท
app.use(logger('dev');
morgan์ ์ฌ์ฉํ ๋ parameter๋ก format ๊ฐ์ ๋ณด๋ด์ค ์ ์๋ค.(์ด ๋ฏธ๋ฆฌ ์ ํด์ง format์ tiny, common, short ๋ฑ ๋ค์ํ๋ค.)
dev format๋ request๋ฅผ ๋ค์๊ณผ ๊ฐ์ ํ์์ผ๋ก console์ ๊ธฐ๋กํด์ค๋ค.
:method :url :status :response-time ms - :res[content-length]
dev format์ ์ฌ์ฉํ์ ๋์ ๋ชจ์ต์ด๋ค.
morgan์ ์ฌ์ฉํ๋ฉด ์๋ฌ๊ฐ ์ด๋ค ์์ฒญ์์ ๋ฐ์ํ๋์ง ํ์ธํ ์ ์์ด์ ๋งค์ฐ ์ ์ฉํ๋ค. ๊ทผ๋ฐ ๋ง์ผ ์ค์ ์๋น์ค๋ฅผ ๋ฐฐํฌํ ์ํ์์ ์๋ฒ์ ์ํ๋ฅผ ์ฝ์๋ก๋ง ํ์ธํ๋ค๋ฉด ๋ก๊ทธ๋ฅผ ๋ชจ๋ ํ์ธํ๋๋ฐ ์ด๋ ค์์ด ์๋ค.
๐ฏ๊ฟํ ๐ฏ
morgan์ console ๋์ file์ logging ํ๋๋ก ์ค์ ์ด ๊ฐ๋ฅํ๋ค.
rotating-file-stream์ด๋ผ๋ ๋ฏธ๋ค์จ์ด๋ฅผ ์ฌ์ฉํ๋ฉด ๋งค์ผ ๋ค๋ฅธ ํ์ผ์ ๋ก๊น ์ ํ ์ ์๋๋ก ์ค์ ํ ์ ์๊ณ ์ฌ์ง์ด๋ console์๋ ์๋ฌ ์์ฒญ๋ง ๊ธฐ๋กํ๋๋ก ํ๊ณ ํ์ผ์๋ ๋ชจ๋ ์์ฒญ์ ๋ค ๊ธฐ๋กํ๋๋ก ์ค์ ํ ์๋ ์๋ค.
๋ค์์ ๊ทธ ์์์ด๋ค!
var express = require('express');
var morgan = require('morgan');
var path = require('path');
var rfs = require('rotating-file-stream'); // version 2.x
var app = express();
// create a rotating write stream
var accessLogStream = rfs.createStream('access.log', {
interval: '1d', // rotate daily
path: path.join(__dirname, 'log'),
});
// log only 4xx and 5xx responses to console
app.use(
morgan('dev', {
skip: function (req, res) {
return res.statusCode < 400;
},
}),
);
// log all requests to access.log
app.use(
morgan('common', {
stream: fs.createWriteStream(path.join(__dirname, 'access.log'), { flags: 'a' }),
}),
);
// ยทยทยท
express-session
express-session์ ์๋ฒ๊ฐ ์ธ์ ์ ์ด์ฉํ๊ฒ ํด์ฃผ๊ณ ์ ์ ์ฟ ํค์ ์ธ์ ์ ๋ณด๋ฅผ ๋ด์ ์ ์๊ฒ ํด์ฃผ๋ ๋งค์ฐ ์ ์ฉํ ๋ฏธ๋ค ์จ์ด์ด๋ค.
์ ์ ์ฟ ํค์ ์ธ์ ์ ๋ณด๋ฅผ ๋ด์ ๋๋ ์ธ์ ์ ๋ชจ๋ ์ ๋ณด๋ฅผ ๋ด๋ ๊ฒ์ด ์๋๋ผ ์ธ์ ์ ์์ด๋ ๊ฐ์ ์ ์ฅํ๊ณ ์๋ฒ์์ ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๊ฒ ๋๋ค.
์ด๋ ์ฌ๋ฌ ์ต์ ์ ์ ํด์ค์ผ ํ๋๋ฐ ์ฃผ์ ์ต์ ์ ํน์ง์ ๋ค์๊ณผ ๊ฐ๋ค.
secret : session Id๋ฅผ hashํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ key ๊ฐ์ด๋ค.(ํด์ฌํ ๊ฐ์ด connect.sid์ ์ ์ฅ๋๋ค.)
resave : ์ธ์ ์ ์ ์ํ ๋๋ง๋ค ์๋ก์ด ์ธ์ ์ ๋ฐ๊ธํ ์ง ๋ง์ง ์ ํ๋ ๊ณณ์ด๋ค.(true ์ค์ ์ race condition์ ๋ฐ์ ์ํฌ ์ ์๋ค๊ณ ํ๋ค. ๋๋ถ๋ถ์ ๊ฒฝ์ฐ false๊ฐ ์ ์ ํ๋ค๊ณ ํ๋ค.)
saveUninitialized : ์ธ์ ID๋ฅผ ๋ฐ๊ธํ์ง ์๋ ์ธ์ ๋ ๋ค ๊ธฐ๋กํ ์ง ์ ํ๋ค.(๋ก๊ทธ์ธ์ ์ฌ์ฉํ ๋๋ ์๋ฒ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์ ์ค์ฌ์ฃผ๊ธฐ ์ํด false๋ก ์ค์ ํ๋ค.)
storage : ์ธ์ ์ ์ด๋์ ์ ์ฅํ ์ง ์ ํ๋ค.(๊ธฐ๋ณธ ๊ฐ์ MemoryStore๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ production์ ์ฌ์ฉํ๋ฉด memory leak์ด ๋ฐ์ํ ์๋ ์๋ค. ์ธ์ ์ ์ ์ฅํ ์ ์๋ ๋ค์ํ storage๊ฐ ์กด์ฌํ๋ค.)
๊ทธ๋ผ ๊ฐ๋จํ ์ด๋ป๊ฒ ๋์๊ฐ๋์ง ํ์ธํด๋ณด์.
๋ค์ ์ฝ๋๋ session ๋ฏธ๋ค์จ์ด๋ฅผ ์ง๋๊ฐ๋ฉด์ ์ด๋ค req์ ์ด๋ค ๋ด์ฉ์ด ์๊ธฐ๋์ง ๋ณด๋ ์ฝ๋์ด๋ค.
var express = require('express');
var session = require('express-session');
var app = express();
function logSessionInfo(req) {
console.log(`req.session : ${req.session}`);
console.log(`req.sessionID : ${req.sessionID}`);
}
app.use(function (req, res, next) {
console.log(`express-session ํต๊ณผ ์ `);
console.log(`req.headers.cookie : ${req.session}`);
logSessionInfo(req);
next();
});
app.use(
session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
}),
);
app.use(function (req, res, next) {
console.log(`express-session ํต๊ณผ ํ`);
logSessionInfo(req);
next();
});
// ยทยทยท
์ถ๋ ฅ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ๋ค.
๐๏ธ์ ๋ฆฌ ๐๏ธ
express-sesssion์ req.headers.cookie์ ์ฃผ์ด์ง sid๋ฅผ sessionID๋ก ๋ฒ์ญํ๊ณ ๊ทธ sessionID์ ํด๋นํ๋ session ๊ฐ์ req.session์ ์ ์ฅํ๊ฒ ๋๋ค!
์ฆ, ์ธ์ ์ ์ ๋ณด ๊ฐ์ ์ฟ ํค์ ์ ๋ฌ๋์ง ์๊ณ ํด์ฌํ๋ sid๋ง ์ ์ ์ ์ฟ ํค์ ์ ์ฅ๋๊ณ ์์ฒญ์ด ๋ค์ด์ค๋ฉด sid๋ฅผ ๋ฒ์ญํ๊ณ ์ป์ session ID์ ํด๋นํ๋ session ๊ฐ์ req.session์ ๋ฃ์ด์ฃผ์ด nextํจ์์์ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋ค!!(์ด์ ์ข ์๊ฒ ๋คโฆใ ใ ใ )
๐ค ๋ณธ๊ฒฉ express๋ก ๋ก๊ทธ์ธ ๊ตฌํํ๊ธฐ
๊ทธ๋ผ ์ด์ ๋ก๊ทธ์ธ ๊ตฌํ์ express์ middleware์ ์์๋ณด๊ณ ๋ก๊ทธ์ธ ํ์ด์ง๋ฅผ ๊ตฌํํด๋ณด์.
passport
passport๋ node์์ ๊ฐ์ฅ ๋ง์ด ์ฐ์ด๋ authentication ๋ฏธ๋ค์จ์ด์ด๋ค. ๊ฐ๋จํ๊ฒ username๊ณผ password๋ฅผ ์ ๊ณตํ๋ ๋ก๊ทธ์ธ ๋ฐฉ๋ฒ๋ถํฐ OpenID์ OAuth ์ ๋ต๋ ์ ๊ณตํ๊ธฐ ๋๋ฌธ์ ๋งค์ฐ ์ ์ฉํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
passport์์ ์ ๊ณตํ๋ ์ฌ๋ฌ strategy๋ฅผ ์ค์นํด์ ์ฌ์ฉํ ์ ์๋ค.
๋ค์๊ณผ ๊ฐ์ด passport์ ํ๋์ Strategy๋ฅผ ๊ฐ์ ธ์์
const passport = require('passport');
const localStrategy = require('passport-local').Strategy;
์ด๋ค ์์ผ๋ก strategy์ ๊ตฌ์ฒด์ ์ธ ๋ด์ฉ์ ์ ์ํ๊ณ passport์ ๋ฃ์ด์ค๋ค.
passport.use(new LocalStrategy(
//verify callback ํจ์
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
// ์์ด๋ ์์
if (!user) {
return donnull, false, { message: 'Incorrect username.' });
}
// ๋น๋ฐ๋ฒํธ ํ๋ฆผ
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
// ์ฑ๊ณต
return done(null, user);
});
}
));
๊ทธ๋ฆฌ๊ณ passport.authenticate๋ฅผ ๋ค์๊ณผ ๊ฐ์ด login request์ ์ฌ์ฉํ ์ ์๋ค.
app.post('/login', passport.authenticate('local'), function (req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/users/' + req.user.username);
});
passport.authentication ํจ์๊ฐ ์ฑ๊ณตํ๋ฉด req.user์ ์ ์ ์ ๋ณด๋ฅผ ๋ฃ์ด์ ์ฝ๋ฐฑ ํจ์๋ฅผ ์คํํ์ง๋ง ๋ก๊ทธ์ธ ์คํจ์ ๋ฐ๋ก 401 authentication error ๋ฉ์์ง๋ฅผ ์ ๋ฌํ๋ค.
โ๊ทธ๋ผ ๋ก๊ทธ์ธ ์ฌ๋ถ๋ ์ด๋์ ๊ฒฐ์ ๋ ๊น?
์์ ์ฝ๋์์ username, password, done์ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ๋ ํจ์๋ verify callback๋ผ๊ณ ํ๋๋ฐ ์ฌ๊ธฐ์ authentication ์ฑ๊ณต๊ณผ ์คํจ ์ฌ๋ถ๋ฅผ doneํจ์๋ก ์ ๋ฌํ๋ค. (์ด๋ ์ ๋ฌ๋ ๊ฐ์ด req.user์ ๋ฃ์ด์ง๋ค.)
์ฑ๊ณต์์๋ done์ ๋๋ฒ์งธ ์ธ์๋ก ์ ์ ์ ๋ณด๋ก ์คํจ์์๋ false๋ฅผ ๋ฐํํ๋ค.
์๋ฌ ๋ฐ์์์๋ ์ฒซ๋ฒ์งธ ์ธ์์ ์๋ฌ๋ฅผ ๋ฃ์ด์ ๋ฐํํ๋ค. // done(err);
โ๋ก๊ทธ์ธ ์ธ์ ์ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด?
passport ๋ํ session์ ์ฌ์ฉํ ์ ์๋ค.
๋ฌด์กฐ๊ฑด session ๋ฏธ๋ค์จ์ด๋ฅผ ์ด์ฉํ ํ์ passport์ session์ ์ฌ์ฉํ๋ค.
app.use(express.session({ secret: 'keyboard cat' }));
app.use(passport.initialize());
app.use(passport.session());
์ธ์ ์ ์ด์ฉํ๊ธฐ ์ํด์๋ serializeUser์ deserializeUser ํจ์๋ฅผ ์ ์ํด์ค์ผ ํ๋ค.
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
๐ฉ serializeUser
verify callback๊ฐ ์ ์ ์ ๋ณด๋ฅผ ์ ๋ฌํ๋ฉด ์คํ๋๋ ํจ์๋ก, ์ฑ๊ณตํ ์ ์ ์ ์ ๋ณด๋ฅผ session์ ์ถ๊ฐํ๋ค.
๐ค deserializeUser
deserializeUser์ Cookie์ ์ ์ฅ๋ passport session ์ ๋ณด๋ฅผ ์ด์ฉํด์ User์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํจ์์ด๋ค.
์์์ session๊ณผ ๊ฐ์ด cookie์๋ ๊ตฌ์ฒด์ ์ธ ์ ์ ์ ๋ณด๊ฐ ๋ด๊ธฐ์ง ์๊ณ passport session id๊ฐ ์ ์ฅ๋์ด ์๋ค.
๐session ์ฌ์ฉ๋์ ์ค์ด๊ธฐ ์ํด์ user์ id๋ง ์ ์ฅํ๊ณ ์์ฒญ์ด ์ค๋ฉด id์ ํด๋นํ๋ ์ ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์์ ์ฐ๋ฉด ์ข๋ค.
โ๊ทธ๋ผ passport session์ ์ ์ ์๊ฒ ์ด๋ป๊ฒ ์ ์ฅ๋ ๊น?
passport์ฉ ์ธ์
์ด ์๋ก ์๊ธฐ๋ ๊ฒ ์๋๋ผ express session์ ํ๋์ property๋ก ๋ค์ด๊ฐ๊ฒ ๋๋ค.
cookie์ ๋ค์ด์๋ express session์ด ์์ฑํ connect.sid์ ํ๋ฉด ๊ทธ ์์ passport session ์ ๋ณด๊ฐ ๋ค์ด์๋ ๊ฑธ ๋ณผ ์ ์๋ค.
โ๋ก๊ทธ์ธ ์ํ์ ๋ฐ๋ผ ํ์ด์ง ์ ๊ทผ ์ ์ดํ๊ธฐ!
๋ง์ดํ์ด์ง์ ๊ฐ์ ํ์ด์ง์ ์ ๊ทผํ ๋๋ ์ ์ ์ ๋ก๊ทธ์ธ ์ํ์ ๋ฐ๋ผ์ ํ์ด์ง๋ฅผ ๋ฌ๋ฆฌ ํด์ค์ผ ํ๋ค.
์ด๋ฐ ์ํฉ์๋ passport์ ์ํด req์ ์์ฑ๋ isAuthenticated๋ฅผ ์ด์ฉํ ์ ์๋ค. ํจ์์ ํํ๋ ๋ค์๊ณผ ๊ฐ๋ค.
req.isAuthenticated = function () {
var property = 'user';
if (this._passport && this._passport.instance) {
property = this._passport.instance._userProperty || 'user';
}
return this[property] ? true : false;
};
์์ ํจ์๋ฅผ ์ด์ฉํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ํจ์๋ฅผ ๋ง๋ค์ด์ ํ์ด์ง๋ฅผ ๋ณด์ฌ์ฃผ๊ธฐ ์ ์ ๋ก๊ทธ์ธ ์ํ๋ฅผ ํ์ธํ์ฌ ๋ก๊ทธ์ธ ๋์ง ์์ req๋ฅผ login page๋ก redirect ํด์ค ์ ์๋ค.
function isAuthenticated(req, res, next) {
if (req.isAuthenticated()) return next();
return res.redirect('/login');
}
// ยทยทยท
router.get('/mypage', isAuthenticated, (req, res) => res.render('mypage', { user: req.user }));
bcrypt
bcrpyt๋ ๋น๋ฐ๋ฒํธ๋ฅผ ์ฝ๊ฒ ์ํธํํด์ฃผ๋ ๋ฏธ๋ค์จ์ด์ด๋ค.
hash๋ฅผ ์์ฑํ ๋๋ bcrypt์ hash ํจ์๋ฅผ ์ด์ฉํ๊ณ ๋น๋ฐ๋ฒํธ๋ฅผ ํ์ธํ ๋๋ compare ํจ์๋ฅผ ์ด์ฉํ๋ค.
const saltRounds = 10;
user.passwordHash = await bcrypt.hash(password, saltRounds);
const match = await bcrypt.compare(password, user.passwordHash);
โbcrpyt๊ฐ ๊ทผ๋ฐ ๋ญ์ง์? ๋น๋ฐ๋ฒํธ ์ํธํ ๊ด๋ จ ์ฌ์ง ์ถ์ฒ ๋ฐ ์ฐธ๊ณ ์๋ฃ
๋น๋ฐ๋ฒํธ๋ฅผ ๋จ๋ฐฉํฅ์ผ๋ก hashing ๋ง์ผ๋ก ์๊ธธ ์ ์๋ ์ ์ถ ๊ฐ๋ฅ์ฑ์ด๋ ๋น ๋ฅธ ์๋๋ก ์ธํด ํด์ปค๋ค์๊ฒ ํธ์์ฑ์ ์ ๊ณตํ ์ ์๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด salt๋ฅผ ๋น๋ฐ๋ฒํธ์ ๋ํ ํ์ hashing์ ์งํํ์ฌ ๋ค์ด์ ์คํธ๋ฅผ ์์ฑํ๋ค.
bcrypt๋ ์ด์ ๋ํด ๋ค์ด์ ์คํธ๋ฅผ ์์ฑํ๋ ๊ณผ์ ์ ๋ช๋ฒ ์งํํ ์ง ๊ฒฐ์ ํ๋ โwork factorโ(์ฌ๊ธฐ์๋ saltRounds์ด๋ค)๋ฅผ ์กฐ์ ํ๋ ๊ฒ ๋ง์ผ๋ก ์์คํ
๋ณด์์ฑ์ ์ฆ๊ฐ์ํจ๋ค๊ณ ํ๋ค.
flash
flash๋ ์ธ์ ์์ ๋ฉ์์ง๋ฅผ ์ ์ฅํ ๋ ์ฌ์ฉํ๋ ํน๋ณํ ๊ณต๊ฐ์ด๋ค.
flash์ ์์ฑ๋ ๋ฉ์์ง๋ ํ๋ฒ ์ ์ ํํ display๋๋ฉด ๋ฐ๋ก ์ญ์ ๋๋ค.
โ์ด๋์ ์ธ๊น? ๋ก๊ทธ์ธ ์คํจ ๋ฉ์์ง ์ ๋ฌ์!
์ฃผ๋ก redirect์ ๋ง์ด ์ฌ์ฉ๋๋๋ฐ ํนํ ๋ก๊ทธ์ธ ์คํจ ์ด์ ๋ฉ์์ง๋ฅผ ๋์ธ ๋ ์ฌ์ฉํ๋ฉด ๋งค์ฐ ์ ์ฉํ๋ค ใ ใ
passport๋ flash๋ฅผ ์ด์ฉํด์ message๋ฅผ ๋์ฐ๋ ๊ฑธ ์ง์ํ๋ค.
verify callback ํจ์๋ฅผ ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด message๋ฅผ ๊ฐ์ด ๋ณด๋ด์ฃผ๊ฒ ๋๋ค. ์ด ๋ถ๋ถ์ flash์ ์ ์ฅ๋๊ฒ ๋๋ค.
// ยทยทยท
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
// ยทยทยท
๊ทธ๋ฆฌ๊ณ req.flash()๋ฅผ ์ด์ฉํด์ ํด๋น ๊ฐ์ ์ ์ ์๊ฒ ์ ๋ฌํ ์ ์๋ค!(ํ๋ฒ ๋ณด์ฌ์ฃผ๋ฉด ์ฌ๋ผ์ง๋ค.)
router.get('/login', (req, res) =>
req.isAuthenticated()
? res.redirect('/mypage')
: res.render('login', { failureMsg: req.flash().error }),
);
๐ ๋ก๊ทธ์ธ ์ ๋ณด ์ ์ฅ์ฉ ํ์ผ ๊ธฐ๋ฐ ๋๋น ๊ตฌํํ๊ธฐ
์ด์ ์ ์ฌ์ฉํ๋ sequelize์ ๊ฐ์ ORM๊ณผ ์ ์ฌํ๊ฒ ํ ์ด๋ธ ํํ๋ฅผ ์ ์ํ๊ณ create, update, getById ํจ์๋ฅผ ๋ด์ฅํ ๋ชจ๋ธ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด์๋ค.
validate ํจ์๋ฅผ ํตํด ์ ์ ๊ฐ ์ ๋ ฅํ ๊ฐ์ด ํ ์ด๋ธ์ attributes์ ํ์ ๊ณผ ์ผ์นํ๋์ง ํ์ธํ๋ ํจ์๋ ๊ตฌํํด๋ดค๋ค ใ ใ
const fs = require('fs');
const path = require('path');
class Model {
static sync = function () {
if (fs.existsSync(this.fileName)) {
const data = fs.readFileSync(this.fileName, 'utf8');
this.items = JSON.parse(data);
}
};
static init = (attributesTypes, { tableName, sync }) => {
this.tableName = tableName;
this.dirname = path.join(__dirname, `../database`);
this.fileName = `${this.dirname}/${tableName}.json`;
this.attributesTypes = attributesTypes;
this.items = [];
if (sync) this.sync();
};
static write = function () {
const data = JSON.stringify(this.items);
if (!fs.existsSync(this.dirname)) fs.mkdirSync(this.dirname);
fs.writeFileSync(this.fileName, data, 'utf8');
};
static validate = function (item) {
const data = {};
for (const [key, value] of Object.entries(item)) {
if (!this.attributesTypes[key] || !value) continue;
switch (this.attributesTypes[key]) {
case 'date':
data[key] = Date(value);
break;
case 'boolean':
data[key] = value == 'on' || value == 1;
break;
case typeof value:
data[key] = value;
break;
default:
throw new Error('User Input Error');
}
}
data.createdAt = Date.now();
data.updatedAt = Date.now();
return data;
};
static getById = (id) => this.items.find((item) => item.id === id);
static create = function (item) {
const validatedItem = this.validate(item);
this.items.push(validatedItem);
this.write();
return validatedItem;
};
static update = function (item) {
const id = this.items.findIndex(item.id);
item.updatedAt = Date.now();
this.items[id] = item;
this.write();
};
static delete = function (item) {
const id = this.items.findIndex(item.id);
item.updatedAt = Date.now();
if (id) this.items[id] = null;
this.write();
};
}
module.exports = Model;
๊ทธ๋ฆฌ๊ณ User table์ ์์ ๋ชจ๋ธ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๋ง๋ค์๋ค:)
const Model = require('./model');
class Users extends Model {
static init() {
return super.init(
{
id: 'string',
pw: 'string',
email: 'string',
name: 'string',
phoneNo: 'string',
address1: 'string',
address2: 'string',
zipCode: 'string',
isAdAgreed: 'boolean',
},
{
tableName: 'Users',
sync: true,
},
);
}
}
module.exports = Users;
๐ฝ๏ธ ํ๋ก์ ํธ ๊นํ ๋ ํฌ์งํ ๋ฆฌ
[์ฐ์ํํ ํฌ์บ ํ] ๋ฐฐ๋ฏผ์ํ ํ์๊ฐ์ /๋ก๊ทธ์ธ ๊ตฌํ ํ๋ก์ ํธ
๐ญ ํ๊ณ
- ์ด๋ฒ ๊ธฐํ๋ฅผ ํตํด์ ์ธ์ ์ด ์ด๋ป๊ฒ ๋์ํ๊ณ ํนํ passport์์ ์ธ์ ์ด ์ด๋ป๊ฒ ์ด์ฉ๋๋์ง ์ข๋ ์ ์ดํดํ ์ ์์๋ ๊ฒ ๊ฐ๋ค.
- ๋ค์์๋ morgan์ ํ์ผ๋ก ๋ก๊น ํ๋๋ฐ ๊น์ง ์ฌ์ฉํด๋ด์ผ๊ฒ ๋ค.
- ๋ชจ๋ฅด๊ณ ์ฌ์ฉํด์ ์ฌ์ค ๋ถ์ํ ๋ถ๋ถ๋ค์ด ๋ง์๋๋ฐ ์ด๋ฒ ๊ธฐํ์ ๊ทธ๋ฐ ๋ถ์ํจ์ด ๋ง์ด ํด์๋ ๊ฒ ๊ฐ์ ๋ณด๋์ฐจ๋ค.
- โ๋ฌด์๋ณด๋ค ํ๋ก ํธ์๋๋ ๋๋ฌด ๋ถ์กฑํ๋ ๋ค์ ๊ธฐํ์๋ ํ๋ก ํธ์๋ ๊ณต๋ถ์๋ ๋ ๋ง์ด ์ ๊ฒฝ์จ๋ด์ผ๊ฒ ๋ค!
์๋ชป ์ ๋ฆฌ๋ ์ ์ด๋ ํผ๋๋ฐฑ ์์ผ๋ฉด ๋ง์ํด์ฃผ์ธ์!