강상위

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

- user password hash 암호화(bcrypt)
- login, logout 기능(passport.js)
- 로그인 사용자만 페이지 액세스(passport - session)
...@@ -75,6 +75,11 @@ ...@@ -75,6 +75,11 @@
75 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 75 "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
76 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 76 "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
77 }, 77 },
78 + "bcrypt-nodejs": {
79 + "version": "0.0.3",
80 + "resolved": "https://registry.npmjs.org/bcrypt-nodejs/-/bcrypt-nodejs-0.0.3.tgz",
81 + "integrity": "sha1-xgkX8m3CNWYVZsaBBhwwPCsohCs="
82 + },
78 "bcrypt-pbkdf": { 83 "bcrypt-pbkdf": {
79 "version": "1.0.2", 84 "version": "1.0.2",
80 "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 85 "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
...@@ -880,6 +885,28 @@ ...@@ -880,6 +885,28 @@
880 "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 885 "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
881 "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 886 "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
882 }, 887 },
888 + "passport": {
889 + "version": "0.4.0",
890 + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz",
891 + "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=",
892 + "requires": {
893 + "passport-strategy": "1.0.0",
894 + "pause": "0.0.1"
895 + }
896 + },
897 + "passport-local": {
898 + "version": "1.0.0",
899 + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz",
900 + "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=",
901 + "requires": {
902 + "passport-strategy": "1.0.0"
903 + }
904 + },
905 + "passport-strategy": {
906 + "version": "1.0.0",
907 + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz",
908 + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ="
909 + },
883 "path-is-absolute": { 910 "path-is-absolute": {
884 "version": "1.0.1", 911 "version": "1.0.1",
885 "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 912 "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
...@@ -890,6 +917,11 @@ ...@@ -890,6 +917,11 @@
890 "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 917 "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
891 "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 918 "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
892 }, 919 },
920 + "pause": {
921 + "version": "0.0.1",
922 + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz",
923 + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10="
924 + },
893 "performance-now": { 925 "performance-now": {
894 "version": "2.1.0", 926 "version": "2.1.0",
895 "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 927 "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
13 "author": "", 13 "author": "",
14 "license": "ISC", 14 "license": "ISC",
15 "dependencies": { 15 "dependencies": {
16 + "bcrypt-nodejs": "0.0.3",
16 "body-parser": "^1.18.3", 17 "body-parser": "^1.18.3",
17 "cheerio": "^1.0.0-rc.2", 18 "cheerio": "^1.0.0-rc.2",
18 "ejs": "^2.6.1", 19 "ejs": "^2.6.1",
...@@ -20,6 +21,8 @@ ...@@ -20,6 +21,8 @@
20 "express-session": "^1.15.6", 21 "express-session": "^1.15.6",
21 "iconv": "^2.3.1", 22 "iconv": "^2.3.1",
22 "mongoose": "^5.3.14", 23 "mongoose": "^5.3.14",
24 + "passport": "^0.4.0",
25 + "passport-local": "^1.0.0",
23 "request": "^2.88.0", 26 "request": "^2.88.0",
24 "selenium-webdriver": "^4.0.0-alpha.1" 27 "selenium-webdriver": "^4.0.0-alpha.1"
25 } 28 }
......
1 var express = require('express'); 1 var express = require('express');
2 var app = express(); 2 var app = express();
3 var bodyParser = require('body-parser'); 3 var bodyParser = require('body-parser');
4 -//var session = require('express-session'); 4 +var session = require('express-session');
5 var mongoose = require('mongoose'); 5 var mongoose = require('mongoose');
6 +var passport = require('passport');
6 7
7 //DB연결 8 //DB연결
8 -mongoose.connect('mongodb://username:pwd@1.201.139.92/dbname'); 9 +mongoose.connect('mongodb://username:pwd@host/dbname');
10 +mongoose.Promise = global.Promise;
9 var db = mongoose.connection; 11 var db = mongoose.connection;
10 12
11 //연결실패 13 //연결실패
...@@ -20,10 +22,25 @@ db.once('open', function() ...@@ -20,10 +22,25 @@ db.once('open', function()
20 console.log('Connected!'); 22 console.log('Connected!');
21 }); 23 });
22 24
23 -
24 // DB모델정의 25 // DB모델정의
25 var Users = require('./models/users'); 26 var Users = require('./models/users');
26 27
28 +// session
29 +app.use(session({
30 + secret: 'keyboard cat',
31 + resave: false,
32 + saveUninitialized: true
33 +}));
34 +
35 +// passport setting
36 +require('./passport')(passport);
37 +app.use(passport.initialize());
38 +app.use(passport.session()); //로그인 세션 유지
39 +// 주의! passport.session을 사용하기 전에 app.use(session(~))설정을 해줘야 한다.
40 +// 그렇지 않으면 passport가 session을 사용하지 못한다.
41 +// app.use는 동기식으로 작동하기 때문에 순서에 유의해야한다.
42 +
43 +
27 // ejs사용 44 // ejs사용
28 // json사용설정 45 // json사용설정
29 app.set('view engine','ejs'); 46 app.set('view engine','ejs');
......
1 var mongoose = require('mongoose'); 1 var mongoose = require('mongoose');
2 +var bcrypt = require('bcrypt-nodejs');
2 3
3 var userSchema = mongoose.Schema 4 var userSchema = mongoose.Schema
4 ( 5 (
...@@ -9,5 +10,22 @@ var userSchema = mongoose.Schema ...@@ -9,5 +10,22 @@ var userSchema = mongoose.Schema
9 } 10 }
10 ); 11 );
11 12
13 +// 패스워드 암호화
14 +userSchema.methods.generateHash = function(password)
15 +{
16 + // password hash를 만든다
17 + return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
18 +};
19 +
20 +// 패스워드 검증
21 +userSchema.methods.validPassword = function(password)
22 +{
23 + // 기존의 해쉬값과 들어온 패스워드를 해쉬값으로 만든 값을 비교한다.
24 + // 주의! 기존의 값이 해쉬가 아니라면 비교불가. 따라서 에러.
25 + // 또한 나는 bcrypt를 bcryt로 잘못 썼는데 잘 안보인다... 조심해라...
26 + //var good = bcrypt.hashSync(this.pwd, bcrypt.genSaltSync(8), null);
27 + return bcrypt.compareSync(password, this.pwd);
28 +};
29 +
12 module.exports = mongoose.model('user',userSchema); 30 module.exports = mongoose.model('user',userSchema);
13 31
......
1 +var LocalStrategy = require('passport-local').Strategy;
2 +var Users = require('./models/users');
3 +
4 +module.exports = function(passport)
5 +{
6 + passport.serializeUser(function(user, done)
7 + {
8 + done(null, user.id);
9 + });
10 +
11 + passport.deserializeUser(function(id, done)
12 + {
13 + done(null, id);
14 + /*
15 + Users.findById(id, function(err, user)
16 + {
17 + done(err, user);
18 + });
19 + */
20 + });
21 +
22 + // 회원가입 처리
23 + passport.use('join', new LocalStrategy
24 + (
25 + {
26 + usernameField: 'id',
27 + passwordField: 'pwd',
28 + passReqToCallback: true
29 + },
30 +
31 + function(req, id, pwd, done)
32 + {
33 + Users.findOne({'id':id}, function(err, user)
34 + {
35 + if(err) return done(err);
36 +
37 + // 유저가 있을 경우 처리
38 + if(user)
39 + {
40 + console.log("Duplicated user");
41 + return done(null, false);
42 + }
43 +
44 + // 새로운 유저 DB추가처리
45 + else
46 + {
47 + var newUser = new Users();
48 + newUser.id = id;
49 + newUser.pwd = newUser.generateHash(pwd);
50 +
51 + // 로그인 이외 필요한 값들 추가
52 + newUser.name = req.body.name;
53 +
54 + newUser.save(function(err)
55 + {
56 + if(err) throw err;
57 + return done(null, newUser);
58 + });
59 +
60 + }
61 + });
62 + }));
63 +
64 + // 로그인 처리
65 + passport.use('login', new LocalStrategy
66 + (
67 + {
68 + usernameField: 'id',
69 + passwordField: 'pwd',
70 + passReqToCallback: true
71 + },
72 + function(req, id, pwd, done)
73 + {
74 + Users.findOne({'id': id}, function(err, user)
75 + {
76 + if(err) return done(err);
77 +
78 + // 유저가 없을 시
79 + if(!user)
80 + {
81 + console.log('no user');
82 + return done(null, false);
83 + //return done(null, false, req.flash('loginMessage', '없는 유저입니다..'));
84 + }
85 +
86 + // 틀린 비밀번호
87 + if(!user.validPassword(pwd))
88 + {
89 + console.log('bad password');
90 + return done(null, false);
91 + //return done(null, false, req.flash('loginMessage', '비밀번호가 다릅니다.'));
92 + }
93 +
94 + console.log('login sucess');
95 + return done(null, user);
96 + });
97 + }
98 + ));
99 +
100 +}
...\ No newline at end of file ...\ No newline at end of file
1 module.exports = function(app, Users) 1 module.exports = function(app, Users)
2 { 2 {
3 + var passport = require('passport');
4 +
3 app.get('/', function(req, res) 5 app.get('/', function(req, res)
4 { 6 {
5 - res.render("index"); 7 + // 로그인 중이면 메인페이지로
6 - console.log("The index page!") 8 + if(req.isAuthenticated())
9 + res.redirect("/main");
10 + // 로그인 중이 아니라면 인덱스페이지
11 + else
12 + {
13 + res.render("index");
14 + console.log("The index page!");
15 + }
7 }); 16 });
8 - 17 +
9 // 로그인 수행 - POST 18 // 로그인 수행 - POST
10 - app.post('/login', function(req, res) 19 + app.post('/login', passport.authenticate('login',
11 { 20 {
12 - Users.find({id: req.body.id, pwd: req.body.pwd},{_id: 1}, function(err, user) 21 + successRedirect: '/main',
13 - { 22 + failureRedirect: '/'
14 - if(err) 23 + //failureFlash : true
15 - { 24 + }));
16 - console.log("Error!");
17 - res.send("Error!")
18 - }
19 25
20 - // 매칭정보 없음 - 로그인 실패 26 + // 로그아웃 수행
21 - if(user.length==0) 27 + app.get('/logout', function(req, res)
22 - {
23 - console.log("Login failed!")
24 - res.send("Login_failed");
25 - }
26 -
27 - // 매칭정보 있음 - 로그인 성공
28 - else
29 - {
30 - console.log("Login Success!")
31 - res.redirect("/main");
32 - // main으로 이동
33 - }
34 - });
35 - });
36 -
37 -
38 - // 메인화면 - 로그인 후 기본 검색화면
39 - app.get('/main', function(req,res)
40 { 28 {
41 - res.render("main"); 29 + req.logout();
42 - console.log("The test page!") 30 + res.redirect('/');
43 - }); 31 + })
44 -
45 32
46 33
47 // Join 34 // Join
...@@ -50,30 +37,89 @@ module.exports = function(app, Users) ...@@ -50,30 +37,89 @@ module.exports = function(app, Users)
50 { 37 {
51 res.render("join") 38 res.render("join")
52 }) 39 })
53 - .post(function(req, res) // 실제 Join 수행 - POST 40 + // 실제 Join 수행 - POST
41 + .post(passport.authenticate('join',
54 { 42 {
55 - // user정보 입력 43 + successRedirect: '/main',
56 - var user = new Users(); 44 + failureRedirect: '/',
57 - user.id = req.body.id; 45 + //failureFlash : true
58 - user.pwd = req.body.pwd; 46 + }));
59 - user.name = req.body.name;
60 47
61 - // DB저장 48 +
62 - user.save(function(err) 49 + // 메인화면 - 로그인 후 기본 검색화면으로
50 + app.get('/main', function(req, res)
51 + {
52 + // 로그인 중이라면
53 + if(req.isAuthenticated())
63 { 54 {
64 - if(err) 55 + console.log("Logged in page");
65 - { 56 + res.render("main");
66 - console.log(err); 57 + }
67 - res.send("Error!") 58 + // 로그인 중이 아니라면
68 - } 59 + else res.redirect("/");
69 - else
70 - {
71 - console.log("Join Success");
72 - res.redirect('/');
73 - }
74 - });
75 - });
76 60
61 + });
77 62
78 63
79 -}
...\ No newline at end of file ...\ No newline at end of file
64 +}
65 +
66 +
67 +
68 +
69 +
70 +/*
71 +(구)직접 DB에 저장하기
72 +.post(function(req, res) // 실제 Join 수행 - POST
73 +{
74 + // user정보 입력
75 + var user = new Users();
76 + user.id = req.body.id;
77 + user.pwd = req.body.pwd;
78 + user.name = req.body.name;
79 +
80 + // DB저장
81 + user.save(function(err)
82 + {
83 + if(err)
84 + {
85 + console.log(err);
86 + res.send("Error!")
87 + }
88 + else
89 + {
90 + console.log("Join Success");
91 + res.redirect('/');
92 + }
93 + });
94 +});
95 +*/
96 +
97 +/*
98 +(구)직접 로그인 하기
99 +app.post('/login', function(req, res)
100 +{
101 + Users.find({id: req.body.id, pwd: req.body.pwd},{_id: 1}, function(err, user)
102 + {
103 + if(err)
104 + {
105 + console.log("Error!");
106 + res.send("Error!")
107 + }
108 +
109 + // 매칭정보 없음 - 로그인 실패
110 + if(user.length==0)
111 + {
112 + console.log("Login failed!")
113 + res.send("Login_failed");
114 + }
115 +
116 + // 매칭정보 있음 - 로그인 성공
117 + else
118 + {
119 + console.log("Login Success!")
120 + res.redirect("/main");
121 + // main으로 이동
122 + }
123 + });
124 +});
125 +*/
...\ No newline at end of file ...\ No newline at end of file
......
1 <div class="contents_main"> 1 <div class="contents_main">
2 - <form method="POST" action="/join"> 2 + <h1>This is main</h1>
3 - <label>id:</label><input type="text" name="id"><br/>
4 - <label>pwd:</label><input type="password" name="pwd"><br/>
5 - <label>name:</label><input type="text" name="name"><br/>
6 - <button type="submit">가입</button>
7 - </form>
8 </div> 3 </div>
...\ No newline at end of file ...\ No newline at end of file
......
1 <div class="navigation_main"> 1 <div class="navigation_main">
2 - <button>로그아웃</button> 2 + <a href="/logout"><button>로그아웃</button></a>
3 <button>검색</button> 3 <button>검색</button>
4 <button>마이페이지</button> 4 <button>마이페이지</button>
5 <button>나만의시간표</button> 5 <button>나만의시간표</button>
......