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/tree/lesson3

 

 

세션과 인증

 

 

39. Express Session & Auth 수업소개

 

 

 

 

 

 

40. 미들웨어 express session의 구동

 

express-session 설치

 

https://www.npmjs.com/package/express-session

 

$ npm i express-session



 

 

nodejs/express-session.js

var express = require('express')
var parseurl = require('parseurl')
var session = require('express-session')

var app = express()

app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true
}))

app.use(function (req, res, next) {
    if (!req.session.views) {
        req.session.views = {}
    }

    // get the url pathname
    var pathname = parseurl(req).pathname

    // count the views
    req.session.views[pathname] = (req.session.views[pathname] || 0) + 1

    next()
})

app.get('/foo', function (req, res, next) {
    res.send('you viewed this page ' + req.session.views['/foo'] + ' times')
})

app.get('/bar', function (req, res, next) {
    res.send('you viewed this page ' + req.session.views['/bar'] + ' times')
})

app.listen(3000);

 

실행

$ nodemon nodejs/express-session.js 

 

 

 

 

 

 

41. express-session의 옵션

 

nodejs/express-session.js

var express = require('express')
var parseurl = require('parseurl')
var session = require('express-session')

var app = express()

app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true
}))


app.get('/', function (req, res, next) {
    res.send('Hello session')
})


app.listen(3000, function () {
    console.log("3000!");
});

 

 

 

 

 

mysql을 저장소로 사용하는 'express-mysql-session'을 사용

 

https://m.blog.naver.com/pjok1122/221555161680

 

npm install -s express-mysql-session

 

express-session 설정

설치가 무사히 끝났으면 다음과 같은 방법으로 express-session을 이용할 수 있습니다.

 

var session = require('express-session');                      (1)
var MySQLStore = require('express-mysql-session')(session);    (2)
var options ={                                                 (3)
    host: 'localhost',
    port: 3306,
    user: '',
    password: '',
    database: ''
};
var sessionStore = new MySQLStore(options);                    (4)

app.use(session({                                              (5)
  secret:"asdfasffdas",
  resave:false,
  saveUninitialized:true,
  store: sessionStore                                          (6)
}))

 

(1) express-session 모듈을 로드합니다.

(2) express-mysql-session 모듈을 로드하되, 인자로 session을 넘겨줍니다.

(3) 데이터베이스에 접속하는 것이므로, host, port, user, password, database 정보를 객체로 저장해둡니다.

(4) 앞서 저장한 객체를 MySQLStore() 함수의 인자로 넘겨줍니다. 이 때 생성되는 객체를 sessionStore라는 변수에 저장합니다.

(4) session() 미들웨어를 설치합니다. secret은 keyboard cat으로 랜덤한 값을 입력해줍니다. secret 값은 공개되어서는 안됩니다. resave와 saveUninitialized는 세션을 다시 저장하냐, 초기화하냐 정도의 옵션인 것 같은데 저도 잘 모르겠습니다.. 보통 false와 true로 설정한다고 합니다.

(5) 저장소를 앞서 DB 연결로 생성된 sessionStore 객체로 지정합니다. (제가 지정한 DB에 session 테이블이 생성됨을 확인할 수 있습니다.)

 

 

session 사용하기

(1) 로그인 시 session에 값 넣어주기.

 

app.get('/login', function(req,rsp){    
    var post = req.body;
    db.query('select member.id as id, password, author_id, name from member left join author on member.author_id = author.id where member.id=? and password=?',
    [post.id,post.password], function(err,result){
        if(err) throw err;
        if(result[0]!==undefined){
            req.session.uid = result[0].id;                            (1)
            req.session.author_id = result[0].author_id;
            req.session.isLogined = true;
            //세션 스토어가 이루어진 후 redirect를 해야함.
            req.session.save(function(){                               (2)
                rsp.redirect('/');
            });
        }
    });
}

 

DB에서 데이터를 읽어 사용자가 보낸 Id password와 일치하는지 확인하고 일치한다면 세션에 데이터를 기록하는 코드입니다.

(database에 사용자의 password를 hash 없이 저장하는 행동은 바람직하지 않지만, 우선은 그냥 저장해두었습니다.)

(1) express-session을 사용하면 request.session 이라는 객체가 생성됩니다. 해당하는 객체에 property를 할당함으로써 세션에 값을 줍니다.

(2) 세션을 세션 스토어에 저장이 끝나면 function()이 실행됩니다. save() 부분이 없다면, session store에 저장하는 일보다 redirect가 먼저 실행되어 로그인 상태가 유지가 안되는 버그(?)가 발생할 수 있습니다.

 

 

(2) session 데이터 삭제하기

delete req.session.uid;
delete req.session.isLogined;
delete req.session.author_id;

req.session.save(function(){
    rsp.redirect('/');
});

 

이 방법은 session에 할당되었던 값을 지우는 방법입니다. 이 방법은 세션 자체를 삭제하는 것이 아니므로 DB에 세션값이 삭제되지 않습니다. 위의 코드와 마찬가지로 DB에 반영을 끝낸 후 redirect하는 것이 포인트입니다.

 

req.session.destory(function(err){});



 

이 방법은 express-session의 공식사이트에 나와있는 세션 삭제 방법입니다. 세션을 완전히 삭제하는 것입니다. 세션을 완전히 삭제하기 때문에 웹 브라우저가 웹 사이트에 접속할 때마다 서버로부터 새로운 세션 ID를 할당받습니다.

 

 

 

 

 

 

 

42. express-session의 session 객체

 

nodejs/express-session.js

~

app.get('/', function (req, res, next) {
    console.log(req.session);
    if (req.session.num === undefined) {
        req.session.num = 1;
    } else {
        req.session.num = req.session.num + 1
    }
    res.send('Hello session')
})

~

 

 

 

 

 

 

43. express-session의 session store

 

 

https://www.npmjs.com/package/session-file-store

 

$npx  i session-file-store

or

$yarn add session-file-store

 

nodejs/express-session.js

var express = require('express')
var parseurl = require('parseurl')
var session = require('express-session')
var FileStore = require('session-file-store')(session);

var app = express()

app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true,
    store: new FileStore()
}))

app.get('/', function (req, res, next) {
    console.log(req.session);
    if (req.session.num === undefined) {
        req.session.num = 1;
    } else {
        req.session.num = req.session.num + 1
    }
    res.send('Hello session')
})


app.listen(3000, function () {
    console.log("3000!");
});

 

 

 

 

 

44. 인증구현 - UI 만들기

 

main.js

~
const authRouter = require("./routes/auth");

~


app.use('/auth', authRouter);
~
~

 

 

routes/auth.js

const express = require('express');
const router = express.Router();
const template = require('../lib/template.js');
const path = require('path');
const sanitizeHtml = require('sanitize-html');
const fs = require('fs');


router.get("/login", (req, res) => {

  const title = 'WEB - login';
  const list = template.list(req.list);
  const html = template.HTML(title, list, `
            <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>
          `, '');
  res.send(html);

});



module.exports = router;

 

 

 

 

 

 

 

45. 인증구현 - 로그인 세션구현

 

 

routes/auth.js

const express = require('express');
const router = express.Router();
const template = require('../lib/template.js');
const path = require('path');
const sanitizeHtml = require('sanitize-html');
const fs = require('fs');

const authData = {
  email: "egoing777@gmail.com",
  password: "1111",
  nickanme: 'macaronics'
}

router.get("/login", (req, res) => {
  const title = 'WEB - login';
  const list = template.list(req.list);
  const html = template.HTML(title, list, `
            <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>
          `, '');
  res.send(html);

});


router.post("/login_process", (req, res) => {
  const post = req.body;
  const email = post.email;
  const password = post.password;

  if (email === authData.email && password === authData.password) {

    res.send("Welcome!");
    //res.redirect("/");
  } else {
    res.send("Who?");
  }
});



module.exports = router;

 

 

 

 

 

 

46. 인증구현 - 세션 미들웨어 설치

 

main.js

const express = require('express')
const fs = require('fs');
const bodyParser = require('body-parser')
const compression = require('compression')
const indexRouter = require("./routes/index");
const topicRouter = require("./routes/topic");
const authRouter = require("./routes/auth");
var session = require('express-session')
var FileStore = require('session-file-store')(session);


const app = express()
const port = 3000
const helmet = require('helmet')



app.use(helmet())
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true,
  store: new FileStore()
}))

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


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

});


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

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}`)
})

 

 

 

routes/auth.js

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

const authData = {
  email: "egoing777@gmail.com",
  password: "1111",
  nickanme: 'macaronics'
}

router.get("/login", (req, res) => {
  const title = 'WEB - login';
  const list = template.list(req.list);
  const html = template.HTML(title, list, `
            <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>
          `, '');
  res.send(html);

});


router.post("/login_process", (req, res) => {
  const post = req.body;
  const email = post.email;
  const password = post.password;

  if (email === authData.email && password === authData.password) {
    req.session.is_logined = true;
    req.session.nickname = 'egoing';
    req.session.save(function () {
      res.redirect('/');
    });
  } else {
    res.send("Who?");
  }

});



module.exports = router;

 

 

 

 

 

 

 

47. 인증구현 - 인증상태를 UI에 반영

 

 

routes/index.js

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


function authIsOwner(req, res) {
    if (req.session.is_logined) return true;
    else return false;
}

function authStatusUI(req, res) {
    let authStatusUI = '<a href="/auth/login">login</a>';
    if (authIsOwner(req, res)) {
        authStatusUI = `${req.session.nickname} <a href="/auth/logout">logout</a>`;
    }
    return authStatusUI;
}

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


module.exports = router;

 

 

 

 

 

 

 

 

48. 인증구현 - 로그인상태 UI를 반영 2

 

 

 lib/auth.js

module.exports = {

    isOwner: function (req, res) {
        if (req.session.is_logined) return true;
        else return false;
    },

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


 

 

routes/topic.js

const express = require('express');
const router = express.Router();
const template = require('../lib/template.js');
const path = require('path');
const sanitizeHtml = require('sanitize-html');
const fs = require('fs');
const auth = require("../lib/auth.js")


router.get("/create", (req, res) => {

  const title = 'WEB - create';
  const list = template.list(req.list);
  const html = template.HTML(title, list, `
            <form action="/topic/create_process" method="post">
              <p><input type="text" name="title" placeholder="title"></p>
              <p>
                <textarea name="description" placeholder="description"></textarea>
              </p>
              <p>
                <input type="submit">
              </p>
            </form>
          `, '', auth.statusUI(req, res));
  res.send(html);

});


~

 

 

 

 

 

 

 

49. 인증구현 - 로그아웃

 

routes/auth.js

router.get("/logout", (req, res) => {
  req.session.destroy(function (err) {
    res.redirect("/");
  })
});

 

 

 

 

 

 

 

 

 

50. 인증구현 - 접근제어

.

 

 

  if (!auth.isOwner(req, res)) return res.redirect("/");



 

topic.js

~


router.post("/create_process", (req, res) => {

  if (!auth.isOwner(req, res)) return res.redirect("/");

  const post = req.body;
  const title = post.title;
  const description = post.description;
  fs.writeFile(`data/${title}`, description, 'utf8', function (err) {
    res.redirect(`/topic/${title}`);
  });

});

~

 

 

 

 

 

 

 

 

 

51. 인증구현 - 세션저장

 

 

routes/auth.js

 

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

const authData = {
  email: "egoing777@gmail.com",
  password: "1111",
  nickanme: 'macaronics'
}

router.get("/login", (req, res) => {
  const title = 'WEB - login';
  const list = template.list(req.list);
  const html = template.HTML(title, list, `
            <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);

});


router.post("/login_process", (req, res) => {
  const post = req.body;
  const email = post.email;
  const password = post.password;

  if (email === authData.email && password === authData.password) {
    req.session.is_logined = true;
    req.session.nickname = authData.nickanme;
    req.session.save(function () {
      res.redirect('/');
    });
  } else {
    res.send("Who?");
  }

});



router.get("/logout", (req, res) => {
  req.session.destroy(function (err) {
    res.redirect("/");
  })
});


module.exports = router;

 

 

 

 

 

 

52. 수업을 마치며

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

about author

PHRASE

Level 60  라이트

아무리 바빠도 바늘 허리 매어 쓰지 못한다 , 아무리 바쁘더라도 갖추어야 할 것은 갖추어서 해야 한다는 말.

댓글 ( 4)

댓글 남기기

작성