이번에는 session과 bcrypt를 이용해 로그인/아웃 기능을 구현할겁니다.
우선 필요한 모듈들을 아래 코드로 불러옵니다.
npm install express-session express-mysql-session bcrypt --save
express-session은 session 객체를 req에 추가해주는 모듈, express-mysql-session은 세션 데이터를 mysql 서버에 저장하기 위한 express-session에 의존하는 모듈, bcrypt는 비밀번호 해싱을 위한 모듈입니다.
app.js에서 세션을 이용하기 위해 아래 코드를 추가해줍니다.
세션 스토어를 설정해야 session 데이터를 sql 서버에 저장할 수 있습니다.
const session = require('express-session');
const MySQLStore = require('express-mysql-session')(session);
// create session store
let sessionStore = new MySQLStore({}, mysqlConnection);
app.use(session({
key: 'LoginSession',
secret: 'Secret',
store: sessionStore,
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 60*60*1000
}
}))
우선 로그인 페이지를 만들어주기 위해 views폴더 아래에 login.pug 파일을 아래와 같이 만들어줍니다.
login.pug
extends top-layout
block content
.Login
form(action='login' method='post')
.Login-input
label(for='id') ID
input(type='text' name='id')
br
label(for='id') password
input(type='password' name='password')
.Login-submit
input(type='submit' value='로그인')
top-layout.pug 파일 body 바로 아래에 로그인 페이지로 가는 링크를 만들어줍니다.
if(session)
.Top
.Top-right
if(session.nickname !== undefined)
a(href='/logout') 로그아웃
else
a(href='/login') 로그인
그리고 index.js 파일에 아래와 같이 get요청을 처리해줍니다.
router.get('/login', (req, res) => {
res.render('login', {
session: req.session
});
})
이 사이트에선 어차피 저 혼자만 로그인 할 거기 때문에 ID와 password를 config.env에 저장해 놓을 겁니다.
그런데 패스워드는 평문으로 저장하면 보안이 너무 취약해지므로 bcrypt로 해싱을 한 후 저장할겁니다.
아래 코드를 돌려서 얻은 hash값과 ID를 config.env에 저장해줍니다.
const bcrypt = require('bcrypt');
const saltRounds = 10;
const myPlaintextPassword = 'my password';
bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
console.log(hash)
});
index.js에서 bcrypt.compare 함수를 이용해 비밀번호를 체크하고 session에 nickname을 추가합니다(session.save 함수는 위에서 설정한 session store에 session을 저장합니다).
이후부터는 session에 nickname이 존재하는지 여부에 따라 로그인 여부를 확인할 수 있습니다.
router.post('/login', (req, res) => {
if(req.body.id !== process.env.ID){
res.render('error', {
message: "존재하지 않는 ID입니다."
})
return;
}
bcrypt.compare(req.body.password, process.env.PASSWORD, (err, result) => {
if(err) throw(err);
if(result) {
req.session.nickname = req.body.id;
req.session.save((err) => {
if(err) throw(err);
res.redirect('/');
})
}
else {
res.render('error', {
message: "password가 일치하지 않습니다."
})
return;
}
});
})
로그아웃은 간단하게 session에서 nickname을 제거하는걸로 처리합니다.
router.get('/logout', (req, res) => {
delete req.session.nickname;
req.session.save(()=> {
res.redirect('/');
})
})
아래는 결과입니다.
로그인과 로그아웃이 잘 작동하는 것을 확인할 수 있습니다.
다음에는 글 쓰기/읽기/목록 표시를 다루겠습니다.