iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 25
0
Modern Web

Node.JS - 30 天入門學習筆記系列 第 25

Day25 - session 在 express 上的應用 – 登入實作為例

今天,來到鐵人賽第二十五天。
下午了,所以,不多言了。
我們來看看今天的進度吧。

在上一篇了解了 cookie 如何在 express 中應用, 並且, 實作了登入。
現在,我們來看看 session版,會有什麼不同。

session 在 express 使用, 必須 使用 第三方 模組,我們去express-session 參考其說明與使用方式。
session主要的使用方式是 session(option),有幾個必須知道的事:

Note: session data 並不會儲存在 cookie 裡,cookie 存的是 sessionID.
Note: session data 儲存在 server端,

接下來,官方網站有寫:意思應該是,直接用這個套件,你不用再用cookie-parser了。這個,就留給有時間再來試驗了。

Note: 從 version1.5.0版以後, 它可以不用再被 cookie-parser 綁約了…
這個套件, 可以直接讀寫 cookie 在req及res。
如果你使用express-session 又使用cookie-parser 如session裡設定的secret 不同於 cookie 的簽章,可能會導致錯誤發生。

◎ 接著,我們看看有哪些重要的option
name:在response中,設定的 sessionID cookie 名字。預設是 connect.sid
proxy:當你有設置secure cookie,信任的反向proxy
resave:強制將session存回 session store, 即使它沒有被修改。預設是 true
rolling:強制在每一次回應時,重新設置一個sessionID cookie。到期, 將重置為原始 maxAge, 重新計數時效性。
saveUninitialized:強制將未初始化的session存回 session store,未初始化的意思是它是新的而且未被修改。
store:session在server 端的存放方式,預設 MemoryStore。
cookie:設定sessionID 的cookie相關選項。其選項與我們在cookie介紹一樣。
預設是 { path: ‘/’, httpOnly: true, secure: false, maxAge: null }.
secret(必要選項):用來簽章 sessionID 的cookie, 可以是一secret字串或是多個secret組成的一個陣列。如果是陣列, 只有第一個元素會被 簽到 sessionID cookie裡。而在驗證請求中的簽名時,才會考慮所有元素。

session store 使用

因為 session 是儲存在server端的,所以,我們可以為 Session 設置存放位置。
一般而言,session 可以存放在:
1.記憶體内存
2.cookie本身
3.redis 或 memcached 等缓存中(常見)
4.數據庫中 ex. mongoDB。

這邊,我將示範,在mongoDB 存 session,很簡單,只要3個步驟:

  1. 首先,必須先安裝 express-sessionconnect-mongo (還有更多session儲存的API, 可以參考 https://github.com/expressjs/session#compatible-session-stores)

  2. 安裝好後,我們可以用簡單的 計數器程式 做例子!首先,引入module:

var session = require('express-session');
const MongoStore = require('connect-mongo')(session);
  1. 引入後, 在session相關option設置,加入
    store:new MongoStore({url:’mongodb://localhost:27017/sessiondb’})
    如圖:
    http://ithelp.ithome.com.tw/upload/images/20161225/20103526GRekhRraii.png

如此,大功告成!!
啟動你的 express server ….
接著, 我們可以進入mongo shell 看到,初始化資料庫已經被自動新增,並且,自動幫我們新增sessions collection:

http://ithelp.ithome.com.tw/upload/images/20161225/20103526txK1F7a7Ll.png

當我們網頁重新整理,session被建立了,即刻存到 sessions 去,所以,我們再find() 有資料!!
然而,此sessionID 的生存時間只有1分鐘, 時間一到, 會自動失效, 幫我們清除舊的。
所以, 我們第二次find()時,在sessions collection 已經沒有找到!!


登入實作

我們直接應用上一篇的登入例子,這邊有些不同的設置地方,再加以說明!

  • Step 1. 首先,安裝並載入相關檔案 express, express-session, body-parser, connect-mongo

  • Step 2. 一樣的建立 Login.html 放入 /public/session/ 之下。
    而我們這裡與上一篇的 cookie登入實作,共用同一樣版,所以,這部份不需變動。

要注意: Login.html 的action 記得指向 /session/post
http://ithelp.ithome.com.tw/upload/images/20161225/20103526pMqFR4z0z8.png

  • Step 3. 我們直接引入上一篇 index.js 的程式碼,修改成如下:

seindex.js

var express = require('express');
// 引入 express-session
var session = require('express-session');
// session store
const MongoStore = require('connect-mongo')(session);
 
var bodyParser = require('body-parser');
var routerSession=require('./routes/seloginAPI');
 
var app = express();
 
//set view engine
app.set("view engine","jade")
//set view directory
app.set("views",__dirname+"/views")
 
//將request進來的data 轉成 json()
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
 
// Create a router to handle routes for a set of seloginAPI
// 抓出來, 變成獨立檔案
// -------------------------------------------------------
 
//static file like .js, .json, .xml, html....
app.use(express.static(__dirname+'/public'));
 
// Apply this router on (/cookie)
app.use('/session', routerSession);
 
app.listen(3000,function(){
    console.log('Ready...for 3000');
});
  • Step 4. 引入session 設定,如下:

seindex.js

//設置session相關設定
app.use(session({
  secret: 'recommand 128 bytes random string',
  store:new MongoStore({url:'mongodb://localhost:27017/sessiondb'}),
  resave: false,
  saveUninitialized: true,
  cookie: { maxAge: 600 * 1000 } //10分鐘到期
 
}));

因為我們有設置 store 所以,我們多設定了 resave 及 saveUninitialized 選項。

  • Step 5. 建立一個路由檔案: /rotues/seloginAPI.js
    一樣,分析一下我們要做的事:  
    http://ithelp.ithome.com.tw/upload/images/20161225/201035268lu8nOI1wb.png

接下來,我們將分別說明這三件事:


/rotues/seloginAPI.js

// 表單送出後...
seloginAPI.post('/post', function(req, res) {
    // ...
    if(req.body.firstName=="" || req.body.lastName=="")
    {
        return res.redirect('Login.html');
    }else if(req.body.firstName==req.session.firstName
             && req.body.lastName==req.session.lastName)
               //如果輸入的,在session store已有儲存..
    {
         req.session.time++; //同一連線的登入次數, 就加 1
         return res.redirect('/session');    //就直接導向到...
    }
    else
    {
        //session store裡沒有的,就會重新設置
        req.session.firstName=req.body.firstName;
        req.session.lastName=req.body.lastName;
        req.session.time=1;
          return res.redirect('/session');
    }
 
});

這段程式說明:表單送出後,開始進行條件判斷。
如果 fristName, lastName 其中一個欄位沒有填寫,則再重回登入頁。
否則,再進行下一個條件判斷:只要,兩者輸入,在session store 已有 (在未登出情況下,同一筆連線),表示 session 早已存在,登入次數加1,直接到需要驗證的頁面即可!–(這裡的判別,可以做省略,主要是為了測試store用!)
否則,重新設置session,並導向驗證頁面。


/rotues/seloginAPI.js

var isLogin=false;
// 進入需要驗證的頁面...
seloginAPI.get('/',function(req,res){
    // ...
    var name='guest';
    isLogin=false;
    var Logtime=1;
    if(req.session.firstName && req.session.lastName){
        name=req.session.firstName+ ' '+req.session.lastName;
        isLogin = true;
        Logtime= req.session.time;
    }
 
     res.render('index', { title: 'Express', member:name, logstatus:isLogin,time:Logtime });
});

這段程式說明:
一開始預設,所有的登入狀態 isLogin 都是false,預設的登入者是guest。
如果,我們接收到的 session 皆存在,則改變 登入者姓名 及 登入狀態。
然而,無論有沒有登入,皆會導到 index.jade 樣版,去做呈現。
這邊與cookie的不同, 多了一個測試 進入次數的計數呈現(非必要)


/rotues/seloginAPI.js

// 登出...
seloginAPI.get('/logout', function(req, res) {
 
    req.session.destroy();
    return res.redirect('/session');
});

這段程式說明:
登出時, 所有session清空!爾後, 導向 /session 路由,
因為有這一步,所以,只要上述的測試,只要它有登出,即使在同一連線,進入次數都是1。
(因為,session store 也只是一個暫存我們session的地方,暫時的~)


最後,完成的Demo,畫面像這樣:
http://ithelp.ithome.com.tw/upload/images/20161225/20103526vxaCI5PvLP.png

我們進入mongo shell 看, 確實 王小明在這session 生存時間 10分鐘內,
同一連線下未登出狀態, 登入了3次

http://ithelp.ithome.com.tw/upload/images/20161225/20103526hR5DgnuC9s.png


完整程式檔案可於這裡下載:
https://github.com/circleuniv/login


最後,放上一張,小編在釐清session運作機制的手寫圖(獻醜了)。
http://ithelp.ithome.com.tw/upload/images/20161225/20103526AuOhKoTayZ.jpg


上一篇
Day24 - Cookie在express上的應用—登入實作為例。
下一篇
Day26 - RESTful 架構開發 與 MVC 設計
系列文
Node.JS - 30 天入門學習筆記32

1 則留言

0
jia0
iT邦新手 5 級 ‧ 2018-02-09 14:11:23

剛學nodejs,實作很好懂

我要留言

立即登入留言