Advertisement
Guest User

Untitled

a guest
Jul 5th, 2017
511
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.65 KB | None | 0 0
  1. /**
  2. * Created by kimilsik on 7/5/17.
  3. */
  4. /*
  5.  
  6. federation authentication을 이용하면
  7. 거대 자본에게 보안 문제를 맡기고
  8. 좀더 서비스에 집중할 수 있는 이점이 있다
  9.  
  10. 따라서 내부 정보는 간단하게 식별자정도만 저장하고
  11. 서비스에 필요한 정보만 저장하면 된다
  12.  
  13. 대신 다른 서비스에 종속되는 느낌은 있다
  14.  
  15. 다른 서비스와 interaction 할 수 있는 기회도 있다
  16.  
  17. <script>
  18. window.fbAsyncInit = function() {
  19. FB.init({
  20. appId : '1594918147219732',
  21. cookie : true,
  22. xfbml : true,
  23. version : 'v2.8'
  24. });
  25. FB.AppEvents.logPageView();
  26. };
  27.  
  28. (function(d, s, id){
  29. var js, fjs = d.getElementsByTagName(s)[0];
  30. if (d.getElementById(id)) {return;}
  31. js = d.createElement(s); js.id = id;
  32. js.src = "//connect.facebook.net/en_US/sdk.js";
  33. fjs.parentNode.insertBefore(js, fjs);
  34. }(document, 'script', 'facebook-jssdk'));
  35. </script>
  36.  
  37. FB.getLoginStatus(function(response) {
  38. statusChangeCallback(response);
  39. });
  40.  
  41. app id : 1594918147219732
  42. app secret 은 절대 노출하면 안된다
  43.  
  44. {
  45. status: 'connected',
  46. authResponse: {
  47. accessToken: '...',
  48. expiresIn:'...',
  49. signedRequest:'...',
  50. userID:'...'
  51. }
  52. }
  53.  
  54. app.get('/auth/facebook')...
  55. app.get('/auth/facebook/callback', ...
  56.  
  57. 왜 두개가 필요할까
  58.  
  59. 페이스북에서 확인을 누르면 callback으로 다시 넘어온다. 여러 정보와 함께.
  60.  
  61. /// 왜 언제는 deserialize가 호출되고 언제는 안되는걸까. 이유가 뭘까.
  62.  
  63. users는 배열 -> 메모리에 있으므로 앱이 꺼지면 사라진다.
  64. session은 파일에 있으므로 남아있다.
  65.  
  66. /// permissions -> email 등의 정보를 얻고 싶다면 사용한다.
  67. scope 이용.
  68. scope 을 바꾸면 다시 사용자에게 확인을 한다.
  69. email ->비밀번호를 잊었을 경우 등등..
  70.  
  71. 이메일을 통해 인증하기 등등을 구현해보면 좋다.
  72.  
  73. %% facebook을 통해 로그인한 사람은 어떻게 저장되는가 -> passport.use
  74. */
  75.  
  76. ////////////////////////////////////////////////
  77.  
  78. var users = [
  79. {
  80. //id : 1,
  81. authId : 'local:kimilsik',
  82. username : 'kimilsik',
  83. salt : '8MCJ7P5qiuzs/JlpC/de55fB9SLRgLQdavZ0sciRkAuJDcwCmy1PR95CIqeZXKeHk4XtsyolrFgMcdgWg2UgZA==',
  84. //password : '55bdaf488171cc19b5c67435e6a17c90',// 평문으로 암호가 저장. 암호를 암호화한다. -> terminal 에서 알아냄.
  85. password : '9gyeresaK/nQ//2OnCYMahZ433dNlUSVrYR5Uh1IDkXVcpGJGD35w9P58VOPtHjGwpgCX1sZf4riJH4gR24hKsV+bYNNx8gwEL+/4Sk5J/udCfZ5p3Dmzenisffz1I8IUP2lXNWxsvfJHmO3oXczPhjWuQm7WnyXelCOEWN0ao0=',
  86. displayName :'kimilsik'
  87. },
  88. // {
  89. // username : 'nasuk',
  90. // salt : '1231DFSF%#$#',
  91. // //password : 'ac536f34dc51048d8be54dd1425f2e57',
  92. // password : 'fe3b51034c66598c45cbd1463924a3afc4f1bf47c3f520c75ae9bf346d36114f',
  93. // displayName : 'nasuk'
  94. // }
  95. ];
  96. // data
  97.  
  98. var express = require('express');
  99. var app = express();
  100. var session = require('express-session'); // 모듈
  101. var bodyParser = require('body-parser'); // express는 기본적으로 post방식이 지원이 안되기 때문에 이걸 설치하여야 한다.
  102. var fileStore = require('session-file-store')(session); // file 로 session을 저장하기 위한 것
  103. var fs = require('fs');
  104.  
  105. // for security
  106. var bkfd2Password = require('pbkdf2-password');
  107. var hasher = bkfd2Password();
  108. var assert = require("assert");
  109. var opts = { // opts는 options이다.
  110. password: "helloworld" // hasher 함수는 첫 번째 인자로 객체를 받고 그 객체 안에
  111. // password property가 있다면 그것을 암호화한다는 것을 추론한다.
  112. };
  113. // for security
  114.  
  115. // federation authentication
  116. var passport = require('passport');
  117. var LocalStrategy = require('passport-local').Strategy;
  118. var FacebookStrategy = require('passport-facebook').Strategy;
  119.  
  120. // federation authentication
  121.  
  122. //var app = express();
  123.  
  124. app.use(bodyParser.urlencoded({extended:false}));
  125.  
  126. app.use(session({
  127. secret: 'oiwehrowhvjknasd1@34124901#!@', // random value
  128. resave : true, // session id 를 접속할 때 마다 새로 발급하는지
  129. saveUninitialized : false,
  130. store : new fileStore(), // session데이터를 저장하는 디렉토리를 만든다. 그 이름이 sessions..
  131. //cookie : {
  132. // secure : false,
  133. //}
  134. }));
  135.  
  136. // federation authentication
  137. app.use(passport.initialize());
  138. app.use(passport.session());
  139.  
  140. app.listen(3004, function() {
  141. console.log('connected 3004 port!!!');
  142. });
  143.  
  144. // passport.use(new LocalStrategy(
  145. // //var check = false;
  146. // function(username, password, done) {
  147. // var check = false;
  148. // for (var i = 0; i < users.length; ++i)
  149. // {
  150. // var str = 'local:' + username;
  151. // if (users[i].authId === str)
  152. // {
  153. // hasher({password : password, salt : users[i].salt},
  154. // function(err, pass, salt, hash) {
  155. // if (hash === users[i].password) {
  156. // check = true;
  157. // console.log('localstrategy', users[i]);
  158. //
  159. //
  160. // //done(null, users[i]); // login succeed.
  161. // // 만일 flash를 쓴다면, 세번째 인자로 message를 보내면 그 메시지가 보여진다.
  162. // // null -> error 를 첫 번째 인자로.
  163. // }
  164. // else
  165. // {
  166. // //done(null, false);
  167. // }
  168. // });
  169. // //break;
  170. // }
  171. // }
  172. //
  173. // if (check)
  174. // return done(null, users[i]);
  175. // else
  176. // return done(null, false);
  177. // //done(null, false); // login failure.
  178. // }
  179. // ));
  180.  
  181. passport.use(new LocalStrategy(
  182. //var check = false;
  183. function(username, password, done) {
  184.  
  185. var check = false;
  186. var str = 'local:' + username;
  187. var loginUser;
  188.  
  189. Promise.all(users.map(function(user) {
  190. return new Promise(function (resolve, reject) {
  191. if (user.authId === str) {
  192. hasher({password: password, salt: user.salt},
  193. function (err, pass, salt, hash) {
  194. if (hash === user.password) {
  195. check = true;
  196. loginUser = user;
  197. console.log('localstrategy', loginUser);
  198. resolve();
  199. //done(null, users[i]); // login succeed.
  200. // 만일 flash를 쓴다면, 세번째 인자로 message를 보내면 그 메시지가 보여진다.
  201. // null -> error 를 첫 번째 인자로.
  202. }
  203. else {
  204. resolve();
  205. //done(null, false);
  206. }
  207. });
  208. //break;
  209. } else {
  210. resolve()
  211. }
  212. })
  213. })).then(function() {
  214. if (check) {
  215. done(null, loginUser);
  216. } else {
  217. done(null, false);
  218. }
  219. }).catch(function(err) {
  220. console.log(err);
  221. });
  222. }
  223. ));
  224.  
  225. passport.use(new FacebookStrategy({
  226. clientID : '1594918147219732',
  227. clientSecret : '76a5953a9487bb7e59d025ca9118851f',
  228. callbackURL : "/auth/facebook/callback",
  229. profileFields : ['id', 'email', 'gender', 'link', 'locale', 'name',
  230. 'timezone', 'updated_time', 'verified', 'displayName']
  231. },
  232. function(accessToken, refreshToken, profile, done) {
  233. console.log(profile); // -> id, username, displayName, name.familyName, name.givenName, name.middleName,
  234. // gender, profileUrl, provider 받는다. 이 중 id 가 제일 중요
  235. // 타사 인증을 통해 로그인한 사용자의 경우 다른 방법으로 정보를 접근해야 한다.
  236.  
  237. var auId = 'facebook:'+profile.id;
  238.  
  239. // 이미 존재한다면 안되므로, 존재하는지부터 확인해야 한다.
  240.  
  241. for (var i = 0; i < users.length; ++i)
  242. {
  243. if (users[i].authId === auId)
  244. {
  245. return done(null, users[i]);
  246. }
  247. }
  248.  
  249. var newuser = {
  250. authId:auId,
  251. displayName: profile.displayName, // facebook 으로 로그인해도 이게 있다.
  252. email : profile.emails[0].value
  253. };
  254.  
  255. users.push(newuser);
  256.  
  257. return done(null, newuser);
  258.  
  259.  
  260. // fs.readdir('userdata/' + profile.id, function (err, files) {
  261. // if (err) {
  262. // // 없다면 새로 가입한다.
  263. // var newuser = {
  264. // authId:auId,
  265. // displayName: profile.displayName, // facebook 으로 로그인해도 이게 있다.
  266. // email : profile.emails[0].value
  267. // };
  268. //
  269. // fs.writeFile('/userdata' + profile, newuser, function (err) {
  270. // if (err) {
  271. // console.log('File Write Error : ' + err);
  272. // res.status(500).send('Internal Server Error');
  273. // } else {
  274. // done(null, newuser);
  275. // }});
  276. // } else {
  277. // // there exists a user.
  278. // return done(null, files); // 객체를 어떻게 리턴할까?
  279. // }
  280. // });
  281.  
  282.  
  283.  
  284. // for (var i = 0; i < users.length; ++i)
  285. // {
  286. // if (users[i].authId === auId) {
  287. // // facebook 을 통해 가입한 사용자가 이미 있다.
  288. // return done(null, users[i]);
  289. // }
  290. // }
  291. //users.push(newuser);
  292. //done(null, newuser);
  293. // find user... or create user
  294. }
  295. ));
  296.  
  297.  
  298. passport.serializeUser(function(user, done)
  299. {
  300. console.log('serializeUser', user);
  301. return done(null, user.authId); // passport.use 에서 done이 호출될 때 자동으로 호출된다.
  302. });
  303.  
  304. passport.deserializeUser(function(id, done) {
  305. console.log('deserializeUser', id);
  306.  
  307. for (var i = 0; i < users.length; ++i)
  308. {
  309. //if (users[i].username === id)
  310. if (users[i].authId === id)
  311. {
  312. return done(null, users[i]);
  313. }
  314. }
  315. done('there is no user.');
  316. });
  317.  
  318. // federation authentication
  319.  
  320. app.get('/auth/logout', function(req, res) {
  321. req.logout(); // request 의 logout method 를 호출한다.
  322. //delete req.session.displayName; // javascript command
  323. req.session.save(function()
  324. {
  325. res.redirect('/welcome');
  326. });
  327. });
  328.  
  329. app.get('/welcome', function(req, res) {
  330. // passport 를 이용하여 유저 정보에 접근해야.
  331.  
  332. // passport 는 user라는 객체로 만들어준다.
  333. // login 에서 done객체의 users[i]가 user가 된다.
  334. if (req.user && req.user.displayName)
  335. //if (req.session.displayName)
  336. {
  337. res.send(`
  338. <h1>hello, ${req.user.displayName}</h1>
  339. <a href="/auth/logout">logout</a>
  340. `);
  341. }
  342. else
  343. {
  344. res.send(`
  345. <h1>Welcome</h1>
  346. <a href="/auth/login">Login</a>
  347. <a href="/auth/register">Register</a>
  348. `);
  349. }
  350. });
  351.  
  352. app.get('/auth/facebook', passport.authenticate(
  353. 'facebook',
  354. {
  355. scope : 'email'
  356. }
  357. ));
  358.  
  359. app.get('/auth/facebook/callback', passport.authenticate('facebook',
  360. {
  361. successRedirect : '/welcome',
  362. failureRedirect : '/auth/login'
  363. })
  364. );
  365.  
  366. app.post(
  367. '/auth/login',
  368. passport.authenticate(
  369. 'local',
  370. {
  371. successRedirect: '/welcome',
  372. failureRedirect: '/auth/login',
  373. failureFlash: false // login 페이지로 이동될 때 인증에 실패했다라는 메시지를 보여준다.
  374. // 아직은 복잡도가 높아서 나중에 사용.
  375. }
  376. )
  377. );
  378.  
  379. app.get('/auth/login', function(req, res) { // p태그는 줄바꿈을 위함.
  380. var output = `
  381. <h1>LOGIN</h1>
  382. <form action="/auth/login" method="post">
  383. <p>
  384. <input type="text" name="username" placeholder="username">
  385. </p>
  386. <p>
  387. <input type="password" name="password" placeholder="password">
  388. </p>
  389. <p>
  390. <input type="submit">
  391. </p>
  392. </form>
  393. <a href="/auth/facebook">facebook</a>
  394. `;
  395. res.send(output);
  396. });
  397.  
  398. app.post('/auth/register', function(req, res) {
  399. // hashing by pbkdf2
  400. hasher({password:req.body.password}, function(err, pass, salt, hash) {
  401. var user = {
  402. authId : 'local:'+req.body.username,
  403. salt : salt,
  404. username : req.body.username,
  405. password : hash,
  406. displayName : req.body.displayName
  407. };
  408.  
  409.  
  410. // for (var i = 0; i < users.length; ++i)
  411. // {
  412. // if (users[i].authId === user.authId)
  413. // {
  414. // return done(null, user);
  415. // }
  416. // }
  417. //
  418.  
  419. fs.readdir('userdata/' + user.authId, function(err, files) {
  420. if (err) {
  421. // it's a new user
  422. fs.writeFile('userdata/' + user.authId, user, function(err) {
  423. if (err) {
  424. console.log('File Write Error : ' + err);
  425. res.status(500).send('Internal Server Error');
  426. } else {
  427. req.login(user, function(err) {
  428. req.session.save(function() {
  429. res.redirect('/welcome');
  430. });
  431. });
  432. //res.redirect('/topic/' + title);
  433. }
  434. });
  435. } else {
  436. // the same user exists.
  437. res.redirect('/auth/login');
  438. }
  439. });
  440.  
  441. users.push(user);
  442.  
  443. // passport 가 넣어주는 함수 -> login()
  444. req.login(user, function(err) {
  445. req.session.save(function() {
  446. res.redirect('/welcome');
  447. });
  448. });
  449. });
  450. });
  451.  
  452. app.get('/auth/register', function(req, res)
  453. {
  454. var output = `
  455. <h1>REGISTER</h1>
  456. <form action="/auth/register" method="post">
  457. <p>
  458. <input type="text" name="username" placeholder="username">
  459. </p>
  460. <p>
  461. <input type="password" name="password" placeholder="password">
  462. </p>
  463. <p>
  464. <input type="text" name="displayName" placeholder="displayName">
  465. </p>
  466. <p>
  467. <input type="submit">
  468. </p>
  469. </form>
  470. `;
  471. res.send(output);
  472. });
  473.  
  474. // // file example
  475. // app.get('/topic/new', function(req, res) {
  476. // fs.readdir('data', function(err, files) {
  477. // if (err)
  478. // {
  479. // console.log(err);
  480. // res.status(500).send('Internal Server Error');
  481. // }
  482. // else
  483. // {
  484. // res.render('new', {topics : files});
  485. // }
  486. // });
  487. // //res.render('new');
  488. // });
  489. //
  490. //
  491. // // topic으로 들어온 액션을 라우팅한다.
  492. // app.post('/topic', function(req, res) {
  493. // var title = req.body.title;
  494. // var desc = req.body.description;
  495. //
  496. // fs.writeFile('data/' + title, desc, function(err) {
  497. // if (err)
  498. // {
  499. // console.log('filereaderror :' + err); // err 정보는 사용자에게 보내면 안된다.
  500. // res.status(500).send('Internal Server Error'); // 500 -> error number. for internal use
  501. // }
  502. // else
  503. // {
  504. // // 사용자의 페이지를 옮겨버림...
  505. // res.redirect('/topic/' + title);
  506. // //res.send('success'); // 두번 send할 순 없다??
  507. // //res.send(title + ' , ' + desc);
  508. // }
  509. // });
  510. //
  511. // });
  512. // file example
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement