session정보 mysql에 저장하기 & passport 인증 구현
#서두
안녕하세요 모닝버드입니다. 오늘은 express-mysql-session 모듈을 설치하여 각 사용자의 세션 id를 mysql 데이터베이스에 저장하는 것과 passport의 passport-local 모듈을 사용하여 사용자 인증을 구현하는 것을 공부했습니다.
#express-mysql-session
- npm에 모듈 설치하기
* 명령어 : npm install express-mysql-session --save
- .js 파일에서 모듈 임포트하기
새로운 const 변수에 require('express-mysql-session')을 통해 모듈으 임포트합니다. 그리고 session 설정의 store 부분에 새로운 MySQLStore() 객체를 할당하고 세부적인 설정을 해줍니다.
{
host: 서버주소(domain),
port: 서버상의 mysql 포트 (default는 3306임),
user: 사용자(필자는 local서버를 사용므로 root라고 설정해줌),
password: mysql 비밀번호,
database: mysql 서버에서 생성한 database 이름
}
//express-session const session = require('express-session'); const MySQLStore = require('express-mysql-session')(session); app.use(session({ secret: 'spemnv2395@#lsore*&@#oso3$%^#&#$@#$!', resave: false, saveUninitialized: true, store: new MySQLStore({ host: 'localhost', port: 3306, user: 'root', password: 'newlife4829', database: 'o2' }) }));
- mysql의 o2데이터베이스에 저장된 세션 정보
특정 사용자로 로그인 했을 때 사용자의 username정보가 session data에 담겨집니다.
#passport 모듈 사용하기
- passport와 passport-local 모듈 설치하기
* 명령어 -> npm install passport --save
-> npm install passport-local --save
< passport >
< passport-local >
- 필자가 구현한 소스
아래의 소스는 passport 모듈을 사용하여 login/logout/register을 처리하였다. passport가 성공적으로 작동하면 request 하위 메소드로 login(), logout(), user() 등의 새로운 녀석들이 생성된다. 세션에 접근하는 방법은 req.session.name 으로 접근할 수 이 작동순서는 passport.authenticate() -> passport.serializeUser() -> passport.deserializeUser() 순서로 작동한다. 필자는 console.log를 통하여 확인하였다.
////////////////////////// setting ////////////////////////// //express const express = require('express'); const app = express(); //web server app.listen(4004, () => console.log('hello 4004')); //pug engine app.set('view engine', 'pug'); app.set('views', './views'); app.locals.pretty = true; //static app.use(express.static('static')); //body-parser const bodyParser = require('body-parser'); app.use(bodyParser.urlencoded({extended: true})); //express-session const session = require('express-session'); const MySQLStore = require('express-mysql-session')(session); app.use(session({ secret: 'spemnv2395@#lsore*&@#oso3$%^#&#$@#$!', resave: false, saveUninitialized: true, store: new MySQLStore({ host: 'localhost', port: 3306, user: 'root', password: 'newlife4829', database: 'o2' }) })); //pbkdf2 var pbkdf2Password = require('pbkdf2-password'); var hasher = pbkdf2Password(); //passport var passport = require('passport'); var LocalStrategy = require('passport-local').Strategy; app.use(passport.initialize()); app.use(passport.session()); /////////////////////////// route /////////////////////////// //users var users = [ { username: 'junhyeok', password: 'hWB/AM3MHngW2N0tphhwhSjH1FagibQamovfQCvo7v2sCfxhDoMv8NEtZjHy3hv5gU242zMpymWIkptqVP5BoocBczcKPLrQ9WNpO+I9NjBUxOMgBazjg649mjc+3kbIomkMSWDxvdxshCXbhNiTmD7iNVeCou/RXTmSDv9mZ8M=', displayName: 'Jun', salt: 'nYMlZ4HIiz3A0LF2A9t4Hj8NdrdQm8OOLVKf8zoZj9NGOO0EDINhCJaxsocXflE3pBqMSATj5xY0nnmBHvg7IQ==' } ] //main-page -> login 기능 app.get('/', (req, res) => { if(req.user && req.user.displayName){ res.render('welcome', {dname: req.user.displayName}); } else { res.render('main'); } }); //serializeUser -> LocalStrategy의 done(null, user);을 전달 받음 passport.serializeUser((user, done) => { console.log('serializeUser', user); done(null, user.username); }); //deserializeUser => serializeUser의 done(null, user.username);을 전달받음 passport.deserializeUser((uname, done) => { console.log('deserializeUser', uname); for(var i=0; i로그인 처리 passport.use(new LocalStrategy((username, password, done) => { var uname = username; var pwd = password; for(var i=0; i { if(hash === user.password){ console.log('LocalStrategy', user); done(null, user); } else { done(null, false); } }); } } done(null, false); })); app.post('/', passport.authenticate('local', { successRedirect: '/welcome', failureRedirect: '/welcome', failureFlash: false }) // var uname = req.body.username; // var pwd = req.body.password; // for(var i=0; i { // if(hash === user.password){ // req.session.displayName = user.displayName; // req.session.save(() => { // res.redirect('/welcome'); // }); // } else { // res.render('failLogin'); // } // }); // } // } // res.render('failLogin'); ); //welcome app.get('/welcome', (req, res) => { if(req.user && req.user.displayName){ res.render('welcome', {dname: req.user.displayName}); } else { res.render('failLogin'); } }); //register app.get('/register', (req, res) => { res.render('register'); }); app.post('/register', (req, res) => { var uname = req.body.username; var pwd = req.body.password; var dname = req.body.displayName; hasher({password: pwd}, (err, pass, salt, hash) => { var user = { username: uname, password: hash, displayName: dname, salt: salt } users.push(user); req.login(user, (err) => { req.session.save(() => { res.redirect('/welcome'); }); }); }); }); //logout app.get('/logout', (req, res) => { req.logout(); // logout()으로 인한 session의 delete가 완료 된 후 redirect 실행 req.session.save(() => { res.redirect('/'); }); });
- passport가 작동되는 순서
< console.log 코드 >
< console.log 결과 >