Nodejs

 

생활 코딩 강의 목록 :  https://opentutorials.org/module/3590

인프런 강의 목록 https://www.inflearn.com/course/node-js-express/dashboard

 

 

 

이 수업은 CC 라이센스를 따르고 있으며, 아래 링크 에서도 볼 수 있습니다.
Node.js-Express https://opentutorials.org/course/3370
쿠키와 인증 https://opentutorials.org/course/3387
세션과 인증 https://opentutorials.org/course/3400 passpor.js
https://opentutorials.org/course/3402
다중 사용자 https://opentutorials.org/course/3411 google login https://opentutorials.org/course/3413 facebook login
https://opentutorials.org/course/3414

 

 

WEB2 - Node.js 수업의 예제 코드 바로가기

 

 

소스 :  https://github.com/braverokmc79/Nodejs-master-passpot

 

 

Passport.js

 

 

53. Express Session & Auth 수업소개

 

 

 

const FileStore = require('session-file-store')(session);
/** 세션 파일 저장 방식 FileStore 
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  store: new FileStore()
}));
*/
// session DB 저장 방식 - 테이블이 자동 생성되고 세션이 저장 된다

 

 

54. passport.js 설치

 

 

55. 인증 구현

 

 

56. 자격확인1

 

 

57. 자격확인2

 

 

58. 세션이용1

 

 

59. 세션이용2

 

 

60. 세션이용3

 

 

 

61.로그인 확인

 

 

 

62.로그아웃

 

 

 

 

63.플래쉬 메시지

https://github.com/jaredhanson/connect-flash

 

 

app.get('/flash', function (req, res) {
  req.flash('msg', 'Flash is back!!!');
  res.send("fmsg");
});
app.get('/flash-display', function (req, res) {
  const fmsg = req.flash();
  console.log(fmsg);
  res.send(fmsg);
});

 

 

64.플래쉬 메시지의 적용

 

 

 

 

 

65.리팩토링

 

 

66.수업을 마치며

 

 

 

 

 

 

 

 

1) 공식 문서 참조

 

1) https://www.passportjs.org/

2)https://www.npmjs.com/package/passport

3) https://www.passportjs.org/howtos/password/

4)https://www.passportjs.org/tutorials/password/verify/

5)  https://www.passportjs.org/concepts/authentication/downloads/html/

 

 

 

 

2) 설치

1.  passport 설치

$ npm install passport

 

2. passport-local  설치 

$ npm install passport-local

 

3.  mysql 설치

$npm i mysql

 

4.  express-mysql-session 설치

& npm i express-mysql-session

 

5. flash 설치

$ npm install connect-flash

 

 

 

 

 

3)  mysql 접속 테스트

 

nodejs/mysql.js

const mysql = require('mysql');
// 비밀번호는 별도의 파일로 분리해서 버전관리에 포함시키지 않아야 합니다. 
const connection = mysql.createConnection({
    host: 'localhost',
    user: 'opentutorials',
    password: '1111',
    database: 'opentutorials'
});

connection.connect();

connection.query('SELECT * FROM topic', function (error, results, fields) {
    if (error) {
        console.log(error);
    }
    console.log('The solution is :', results);
});

connection.end();

 

$nodemon  nodejs/mysql.js

 

 

 

4) 설정 주의

app.use    session   설정 다음에 반드시  passport  추가할것

 

const express = require('express')
const fs = require('fs');
const bodyParser = require('body-parser')
const compression = require('compression')
const session = require('express-session')
const MySQLStore = require('express-mysql-session')(session);
const flash = require('connect-flash');
const app = express()
const port = 3000
const helmet = require('helmet')


app.use(helmet())
app.use(express.static('public'))
app.use(bodyParser.urlencoded({ extended: false }));
app.use(compression());


// session DB 저장 방식 - session 테이블이 자동 생성되고  세션이 passport의해 저장 된다.
app.use(session({
  secret: '12312dajfj23rj2po4$#%@#',
  resave: false,
  saveUninitialized: true,
  store: new MySQLStore({
    host: 'localhost',
    port: 3306,
    user: 'opentutorials',
    password: '1111',
    database: 'opentutorials'
  })
}));

app.use(flash());
const passport = require("./lib/passport")(app);

app.get('*', (req, res, next) => {
  fs.readdir('./data', function (error, filelist) {
    req.list = filelist;
    next();
  });
});



~

 

 

 

 

 

5) passport  회원가입 및 로그인 구현

중요하게 볼 파일은 

main.js 파일에  passport 설정 부분, 

 lib/passport.js 

 routes/auth.js  

파일이다.

 

 

const express = require('express')

const session = require('express-session')
const MySQLStore = require('express-mysql-session')(session);
const flash = require('connect-flash');
const app = express()
const port = 3000

~


// session DB 저장 방식 - session 테이블이 자동 생성되고  세션이 passport의해 저장 된다.
app.use(session({
  secret: '12312dajfj23rj2po4$#%@#',
  resave: false,
  saveUninitialized: true,
  store: new MySQLStore({
    host: 'localhost',
    port: 3306,
    user: 'opentutorials',
    password: '1111',
    database: 'opentutorials'
  })
}));

app.use(flash());
const passport = require("./lib/passport")(app);

const authRouter = require("./routes/auth")(passport);
app.use('/auth', authRouter);



~


 

1. main.js

const express = require('express')
const fs = require('fs');
const bodyParser = require('body-parser')
const compression = require('compression')
const session = require('express-session')
const MySQLStore = require('express-mysql-session')(session);
const flash = require('connect-flash');
const app = express()
const port = 3000
const helmet = require('helmet')


app.use(helmet())
app.use(express.static('public'))
app.use(bodyParser.urlencoded({ extended: false }));
app.use(compression());


// session DB 저장 방식 - session 테이블이 자동 생성되고  세션이 passport의해 저장 된다.
app.use(session({
  secret: '12312dajfj23rj2po4$#%@#',
  resave: false,
  saveUninitialized: true,
  store: new MySQLStore({
    host: 'localhost',
    port: 3306,
    user: 'opentutorials',
    password: '1111',
    database: 'opentutorials'
  })
}));

app.use(flash());
const passport = require("./lib/passport")(app);

app.get('*', (req, res, next) => {
  fs.readdir('./data', function (error, filelist) {
    req.list = filelist;
    next();
  });
});


const indexRouter = require("./routes/index");
const authRouter = require("./routes/auth")(passport);
const topicRouter = require("./routes/topic");

app.use("/", indexRouter);
app.use('/auth', authRouter);
app.use('/topic', topicRouter);



app.use(function (req, res) {
  res.status(400).send("Sorry cant find that!");
});

app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

 

 

2. lib/db.js

const mysql = require('mysql');
const db = mysql.createConnection({
    host: 'localhost',
    user: 'opentutorials',
    password: '1111',
    database: 'opentutorials'
});
db.connect();

module.exports = db;

 

 

3. lib/auth.js

module.exports = {

    isOwner: function (req, res) {
        console.log(" isOwner req.user : ", req.user);
        if (req.user) return true;
        else return false;
    },

    statusUI: function (req, res) {
        let authStatusUI = '<a href="/auth/login">login</a>&nbsp;&nbsp;<a href="/auth/signup">signup</a>';
        if (this.isOwner(req, res)) {
            authStatusUI = `${req.user.username}  <a href="/auth/logout">logout</a>
           
            `;
        }
        return authStatusUI;
    }
}


 

★현재 프로젝트에서는 적용하지 않았으나,

 passReqToCallback: true 옵션값을 넣어 req  파라미터값을 사용할 수 있다.

passport.use(new LocalStrategy({
    usernameField: 'email',
    passwordField: 'password',
    passReqToCallback: true
}, function verify(req, email, password, done) {
    console.log('local-join callback called');
    console.log(email, password, done);
}
));

 

 

4. lib/passport.js

const passport = require("passport");
const crypto = require('crypto');
const db = require("../lib/db");
const LocalStrategy = require('passport-local');

module.exports = function (app) {
    app.use(passport.initialize());
    app.use(passport.session());

    passport.serializeUser(function (user, cb) {
        console.log("로그인 처리시 최초 한번  passport.serializeUser 호출 user 값  :", user);
        process.nextTick(function () {
            cb(null, { id: user.id, username: user.username });
        });
    });

    // 로그인 성공되면 passport.deserializeUser  매번 실행 처리된다
    passport.deserializeUser(function (user, cb) {
        console.log("deserializeUser  :", user);
        process.nextTick(function () {
            return cb(null, user);
        });
    });


    // 로그인 처리 - 2) passport 로그인
    passport.use(new LocalStrategy({
        usernameField: 'email',
        passwordField: 'password'
    }, function verify(email, password, cb) {

        db.query('SELECT * FROM users WHERE email = ?', [email], function (err, row) {
            if (err) { return cb(err); }
            if (!row[0]) { return cb(null, false, { message: '등록된 이메일이 없습니다.' }); }

            crypto.pbkdf2(password, row[0].salt, 310000, 32, 'sha256', function (err, hashedPassword) {
                console.log("로그인 데이터 : ", password, row[0].salt, hashedPassword.toString('hex'));
                console.log("로그인 DB암호: ", row[0].hashed_password);

                if (err) { return cb(err); }
                if (row[0].hashed_password !== hashedPassword.toString('hex')) {
                    console.log("비밀번호 오류");
                    //flash 에 저장 처리됨  - "flash":{"error":["비밀번호가 일치하지 않습니다."]}}
                    return cb(null, false, { message: '비밀번호가 일치하지 않습니다.' });
                }


                console.log("로그인 성공");
                return cb(null, row[0], { message: '로그인 성공' });
            });
        });

    }));


    return passport;
}

 

 

 

5. routes/auth.js

const express = require('express');
const router = express.Router();
const template = require('../lib/template.js');
const auth = require("../lib/auth.js");
const db = require("../lib/db");
global.crypto = require('crypto')

module.exports = function (passport) {

  //로그인 페이지
  router.get("/login", (req, res) => {
    const fmsg = req.flash();
    let feedback = '';
    if (fmsg.error) {
      feedback = fmsg.error[0];
    }

    const title = 'WEB - login';
    const list = template.list(req.list);
    const html = template.HTML(title, list, `
            <div style="color:red">${feedback}</div>
            <form action="/auth/login_process" method="post">
              <p><input type="email" name="email" placeholder="email"></p>  
              <p><input type="password" name="password" placeholder="password"></p>                                 
              <p>
                <input type="submit" value="login">
              </p>
            </form>
          `, '', auth.statusUI(req, res));
    res.send(html);

  });


  // 로그인 처리 - 1) 성공 및 실패 페이지 설정 및 flash 사용여부 설정하기
  router.post('/login_process', passport.authenticate('local', {
    successRedirect: '/',
    failureRedirect: '/auth/login',
    failureFlash: true,
    successFlash: true
  }));


  //로그 아웃 처리
  router.get('/logout', function (req, res, next) {
    req.logout(function (err) {
      if (err) { return next(err); }

      req.session.destroy(function (err) {
        res.redirect("/");
      })
    });
  });


  //회원가입페이지
  router.get('/signup', function (req, res, next) {
    const fmsg = req.flash();
    let feedback = '';
    console.log("회원 가입페이지 : ", fmsg);
    if (fmsg.error) {
      feedback = fmsg.error[0];
    }

    const title = 'WEB - login';
    const list = template.list(req.list);
    const html = template.HTML(title, list, `
      <div style="color:red">${feedback}</div>
           <h1>Sign up</h1>
      <form action="/auth/signup_process" method="post">
          <section>
              <label for="username">이름</label>
              <input id="username" name="username" type="text" placeholder="이름" required>
          </section>
         <section>
              <label for="email">이메일</label>
              <input id="email" name="email" type="email" placeholder="이메일" required>
          </section>          
          <section>
              <label for="password">비밀번호</label>
              <input id="password" name="password" type="password" autocomplete="new-password" placeholder="비밀번호" required>
          </section>
          <section>
              <label for="password">비밀번호확인</label>
              <input id="password" name="pw2" type="password" autocomplete="new-password" placeholder="비밀번호확인" required>
          </section>          
          <button type="submit">Sign up</button>
      </form>
          `, '', auth.statusUI(req, res));
    res.send(html);
  });


  //회원가입처리
  router.post('/signup_process', function (req, res, next) {

    if (req.body.password !== req.body.pw2) {
      req.flash("error", "비밀번호가 일치 하지 않습니다.");
      return res.redirect("/auth/signup");
    }
    crypto.randomBytes(16, (error, buf) => {
      const salt = buf.toString("base64");

      crypto.pbkdf2(req.body.password.trim(), salt, 310000, 32, 'sha256', function (err, hashedPassword) {
        console.log("회원가입 데이터 : ", req.body.password, salt, hashedPassword.toString('hex'));

        if (err) { return next(err); }
        db.query('INSERT INTO users (username,email, hashed_password, salt) VALUES (?, ?, ?, ?)', [
          req.body.username,
          req.body.email,
          hashedPassword.toString('hex'),
          salt
        ], function (err, results, fields) {

          if (err) {
            req.flash("error", err.toString());
            return res.redirect('/auth/signup');
          }

          var user = {
            id: this.lastID,
            username: req.body.username
          };

          console.log("등록한 insertId :", results.insertId);

          req.login(user, function (err) {
            if (err) { return next(err); }
            req.flash("success", "회원가입을 축하합니다.");
            res.redirect('/');
          });


        });
      });


    });
  });


  return router;
}

 

 

 

 

 

6.routes/index.js

const express = require('express');
const router = express.Router();
const template = require('../lib/template.js');
const auth = require("../lib/auth.js")


router.get('/', (req, res) => {
    const fmsg = req.flash();

    let feedback = '';
    if (fmsg.success) {
        feedback = fmsg.success[0];
    }

    let title = 'Welcome';
    const description = 'Hello, Node.js';
    const list = template.list(req.list);
    const html = template.HTML(title, list,
        `
        <div style="color:blue">${feedback}</div>
        <h2>${title}</h2>${description}   
     <img src="/images/hello.jpg" style="width:300px; display:block; margin-top:10px" >
    `,
        `<a href="/topic/create">create</a>`,
        auth.statusUI(req, res)
    );
    res.send(html);
});


module.exports = router;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

참으로 자녀를 아는 아버지는 그야말로 현명한 사람이다. -셰익스피어

댓글 ( 4)

댓글 남기기

작성