강상위

인증기능 완성 - passport.js + bcrypt(3개 기능)

- user password hash 암호화(bcrypt)
- login, logout 기능(passport.js)
- 로그인 사용자만 페이지 액세스(passport - session)
......@@ -75,6 +75,11 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"bcrypt-nodejs": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz",
"integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
......@@ -880,6 +885,28 @@
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
"integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
},
"passport": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz",
"integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=",
"requires": {
"passport-strategy": "1.0.0",
"pause": "0.0.1"
}
},
"passport-local": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
"integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
"requires": {
"passport-strategy": "1.0.0"
}
},
"passport-strategy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
"integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
......@@ -890,6 +917,11 @@
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
"integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
},
"pause": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
"integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
......
......@@ -13,6 +13,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt-nodejs": "0.0.3",
"body-parser": "^1.18.3",
"cheerio": "^1.0.0-rc.2",
"ejs": "^2.6.1",
......@@ -20,6 +21,8 @@
"express-session": "^1.15.6",
"iconv": "^2.3.1",
"mongoose": "^5.3.14",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"request": "^2.88.0",
"selenium-webdriver": "^4.0.0-alpha.1"
}
......
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
//var session = require('express-session');
var session = require('express-session');
var mongoose = require('mongoose');
var passport = require('passport');
//DB연결
mongoose.connect('mongodb://username:pwd@1.201.139.92/dbname');
mongoose.connect('mongodb://username:pwd@host/dbname');
mongoose.Promise = global.Promise;
var db = mongoose.connection;
//연결실패
......@@ -20,10 +22,25 @@ db.once('open', function()
console.log('Connected!');
});
// DB모델정의
var Users = require('./models/users');
// session
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true
}));
// passport setting
require('./passport')(passport);
app.use(passport.initialize());
app.use(passport.session()); //로그인 세션 유지
// 주의! passport.session을 사용하기 전에 app.use(session(~))설정을 해줘야 한다.
// 그렇지 않으면 passport가 session을 사용하지 못한다.
// app.use는 동기식으로 작동하기 때문에 순서에 유의해야한다.
// ejs사용
// json사용설정
app.set('view engine','ejs');
......
var mongoose = require('mongoose');
var bcrypt = require('bcrypt-nodejs');
var userSchema = mongoose.Schema
(
......@@ -9,5 +10,22 @@ var userSchema = mongoose.Schema
}
);
// 패스워드 암호화
userSchema.methods.generateHash = function(password)
{
// password hash를 만든다
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
// 패스워드 검증
userSchema.methods.validPassword = function(password)
{
// 기존의 해쉬값과 들어온 패스워드를 해쉬값으로 만든 값을 비교한다.
// 주의! 기존의 값이 해쉬가 아니라면 비교불가. 따라서 에러.
// 또한 나는 bcrypt를 bcryt로 잘못 썼는데 잘 안보인다... 조심해라...
//var good = bcrypt.hashSync(this.pwd, bcrypt.genSaltSync(8), null);
return bcrypt.compareSync(password, this.pwd);
};
module.exports = mongoose.model('user',userSchema);
......
var LocalStrategy = require('passport-local').Strategy;
var Users = require('./models/users');
module.exports = function(passport)
{
passport.serializeUser(function(user, done)
{
done(null, user.id);
});
passport.deserializeUser(function(id, done)
{
done(null, id);
/*
Users.findById(id, function(err, user)
{
done(err, user);
});
*/
});
// 회원가입 처리
passport.use('join', new LocalStrategy
(
{
usernameField: 'id',
passwordField: 'pwd',
passReqToCallback: true
},
function(req, id, pwd, done)
{
Users.findOne({'id':id}, function(err, user)
{
if(err) return done(err);
// 유저가 있을 경우 처리
if(user)
{
console.log("Duplicated user");
return done(null, false);
}
// 새로운 유저 DB추가처리
else
{
var newUser = new Users();
newUser.id = id;
newUser.pwd = newUser.generateHash(pwd);
// 로그인 이외 필요한 값들 추가
newUser.name = req.body.name;
newUser.save(function(err)
{
if(err) throw err;
return done(null, newUser);
});
}
});
}));
// 로그인 처리
passport.use('login', new LocalStrategy
(
{
usernameField: 'id',
passwordField: 'pwd',
passReqToCallback: true
},
function(req, id, pwd, done)
{
Users.findOne({'id': id}, function(err, user)
{
if(err) return done(err);
// 유저가 없을 시
if(!user)
{
console.log('no user');
return done(null, false);
//return done(null, false, req.flash('loginMessage', '없는 유저입니다..'));
}
// 틀린 비밀번호
if(!user.validPassword(pwd))
{
console.log('bad password');
return done(null, false);
//return done(null, false, req.flash('loginMessage', '비밀번호가 다릅니다.'));
}
console.log('login sucess');
return done(null, user);
});
}
));
}
\ No newline at end of file
module.exports = function(app, Users)
{
var passport = require('passport');
app.get('/', function(req, res)
{
res.render("index");
console.log("The index page!")
// 로그인 중이면 메인페이지로
if(req.isAuthenticated())
res.redirect("/main");
// 로그인 중이 아니라면 인덱스페이지
else
{
res.render("index");
console.log("The index page!");
}
});
// 로그인 수행 - POST
app.post('/login', function(req, res)
app.post('/login', passport.authenticate('login',
{
Users.find({id: req.body.id, pwd: req.body.pwd},{_id: 1}, function(err, user)
{
if(err)
{
console.log("Error!");
res.send("Error!")
}
successRedirect: '/main',
failureRedirect: '/'
//failureFlash : true
}));
// 매칭정보 없음 - 로그인 실패
if(user.length==0)
{
console.log("Login failed!")
res.send("Login_failed");
}
// 매칭정보 있음 - 로그인 성공
else
{
console.log("Login Success!")
res.redirect("/main");
// main으로 이동
}
});
});
// 메인화면 - 로그인 후 기본 검색화면
app.get('/main', function(req,res)
// 로그아웃 수행
app.get('/logout', function(req, res)
{
res.render("main");
console.log("The test page!")
});
req.logout();
res.redirect('/');
})
// Join
......@@ -50,30 +37,89 @@ module.exports = function(app, Users)
{
res.render("join")
})
.post(function(req, res) // 실제 Join 수행 - POST
// 실제 Join 수행 - POST
.post(passport.authenticate('join',
{
// user정보 입력
var user = new Users();
user.id = req.body.id;
user.pwd = req.body.pwd;
user.name = req.body.name;
successRedirect: '/main',
failureRedirect: '/',
//failureFlash : true
}));
// DB저장
user.save(function(err)
// 메인화면 - 로그인 후 기본 검색화면으로
app.get('/main', function(req, res)
{
// 로그인 중이라면
if(req.isAuthenticated())
{
if(err)
{
console.log(err);
res.send("Error!")
}
else
{
console.log("Join Success");
res.redirect('/');
}
});
});
console.log("Logged in page");
res.render("main");
}
// 로그인 중이 아니라면
else res.redirect("/");
});
}
\ No newline at end of file
}
/*
(구)직접 DB에 저장하기
.post(function(req, res) // 실제 Join 수행 - POST
{
// user정보 입력
var user = new Users();
user.id = req.body.id;
user.pwd = req.body.pwd;
user.name = req.body.name;
// DB저장
user.save(function(err)
{
if(err)
{
console.log(err);
res.send("Error!")
}
else
{
console.log("Join Success");
res.redirect('/');
}
});
});
*/
/*
(구)직접 로그인 하기
app.post('/login', function(req, res)
{
Users.find({id: req.body.id, pwd: req.body.pwd},{_id: 1}, function(err, user)
{
if(err)
{
console.log("Error!");
res.send("Error!")
}
// 매칭정보 없음 - 로그인 실패
if(user.length==0)
{
console.log("Login failed!")
res.send("Login_failed");
}
// 매칭정보 있음 - 로그인 성공
else
{
console.log("Login Success!")
res.redirect("/main");
// main으로 이동
}
});
});
*/
\ No newline at end of file
......
<div class="contents_main">
<form method="POST" action="/join">
<label>id:</label><input type="text" name="id"><br/>
<label>pwd:</label><input type="password" name="pwd"><br/>
<label>name:</label><input type="text" name="name"><br/>
<button type="submit">가입</button>
</form>
<h1>This is main</h1>
</div>
\ No newline at end of file
......
<div class="navigation_main">
<button>로그아웃</button>
<a href="/logout"><button>로그아웃</button></a>
<button>검색</button>
<button>마이페이지</button>
<button>나만의시간표</button>
......