iT邦幫忙

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

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

Day24 - Cookie在express上的應用—登入實作為例。

今天,來到鐵人賽第二十四天。
話說,今日是聖誕夜。
天氣晴,可真是另類之聖誕節。
是啊,誰說聖誕節一定要下雪的?!
這麼熱血,來打鐵!
我們開始囉~

當我們了解了Cookie運作與機制,現在,我們來看看express上如何使用 cookie 做 登入。
首先,我們進入 express的官網看到,它提供了幾個cookie相關的API 參考

Response (server設定cookie,回傳給client)

res.cookie(name, value [, options])

這個有三個參數:
name: 設定cookie的名字
value: 設定其值,可能是字串或是轉成JSON格式的物件。
options: 選項參數是一個物件,所以,其屬性放在{}裡,以逗號分隔。

◎ 分別有哪些不同的屬性
domain (字串) 適用此cookie的domain name
encode (函式) 用於cookie編碼的同步函式,預設encodeURIComponent.
expires (日期) cookie的到期日,超過此日期,即失效。
httpOnly (布林) 標記此cookie只能從web server 訪問,以避免不正確的進入來取得竄改。
maxAge (數字) 設定此cookie的生存時間(毫秒為單位),比方60000(10分鐘後到期,必須重新訪問)
path (字串) 適用此cookie的路徑,預設: “/”.
secure (布林) 設定此cookie是否只在https使用。
signed (布林) 此cookie是否要設簽章。(如果是true,必須使用cookie-parser設定簽章 )

res.clearCookie(name [, options])

清除cookie(登出時,可用此方法,選項與上相同)

Request (向client接收cookie)

req.signedCookies

取得由client端接收過來有設定簽章的請求,讓它形成未簽章並加以使用。
有加上簽章的cookie,好處是,只有開發者自己知道的簽章加上回應出去給個別oookie 時,使用者根本不知道你開發者簽了什麼,要竄改也難。否則,惡意攻擊容易放入req.cookie。

ex. 接收過來的 Cookie: user= ladykaka.CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3
當後面這一串 .CP7AWaXDfAKIRfH49dQzKJx7sKzzSoPq7/AcBBRVwlI3 簽章與開發人員設定的簽章有相應,req.signedCookies.user 的值即為: ladykaka

設定簽章

express設定簽章,必須使用 cookie-parser middleware,它的作用是即為cookie做一個簽章。
用法:在你的express物件,加入cookieParser(your sign) 即可!
參數your sign建議是一個 128 bytes 的隨機字串。

例如:

var app=express();
app.use(cookieParser('123456789'));

登入實作

接下來,我們來從無到有,實作一個express web app 並使用cookie 登入驗證功能:

  • Step1. 建立一個專案資料夾 login,並且初始化:
    mkdir login
    cd login
    npm init  

經過初始化以後的login資料夾,就是整個login專案!

  • Step2. 安裝這篇必要的第三方 module,記得加 –save參數,寫入package.json:
    這裡需要有 express, body-parser, cookie-parse
    npm install express --save
    npm install body-parser --save
    npm install cookie-parser --save
  • Step3. 根據先前所學,把Login.html 靜態網頁建立好,放置在 /public/cookie/底下:
    jade 樣版建立好,放置在 /views/底下。(這邊就不贅述了)

    比較值得一提,login.html , post 之後的路徑,應設為:
    http://ithelp.ithome.com.tw/upload/images/20161224/20103526WVgc2bgVix.png

    接著,我們建立一個express web server

    index.js

//載入第三方模組
var express = require('express');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
 
//載入路由檔案
var routerCookie=require('./routes/loginAPI');
 
var app = express(); //建立一個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 loginAPI
// 抓出來, 變成獨立檔案
// -------------------------------------------------------
 
//靜態檔案 like .js, .json, .xml, html....
app.use(express.static(__dirname+'/public'));
 
// 允許 /cookie 使用這個路由
app.use('/cookie', routerCookie);
 
app.listen(3000,function(){
    console.log('Ready...for 3000');
});
  • Step4. 接下來,重頭戲來了,上方檔案,再加入一個簽章:

index.js

// sign for cookie
app.use(cookieParser('123456789'));

如圖:
http://ithelp.ithome.com.tw/upload/images/20161224/20103526wun9H7XdiI.png

  • Step5. 建立一個路由檔案: /rotues/loginAPI.js

我們要做的事,如圖:
http://ithelp.ithome.com.tw/upload/images/20161224/20103526RS6gJ7JXBK.png

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


/rotues/loginAPI.js

// 表單送出後...
loginAPI.post('/post', function(req, res) {
   // ...
   if(req.body.firstName=="" || req.body.lastName=="")
   {
            return res.redirect('Login.html');
   }else{
       res.cookie('firstName', req.body.firstName, { path: '/cookie', signed: true, maxAge:600000});  //set cookie
       res.cookie('lastName', req.body.lastName, { path: '/cookie', signed: true, maxAge:600000 }); //set cookie
       return res.redirect('/cookie');
   }
}); 

這段程式說明:
如果表單送出後,只要fristName, lastName 其中一個欄位沒有填寫,則再重回登入頁。
如果都有填了,則可以建立 cookie,在 /cookie之下有效,使用簽章,cookie 生存值100分鐘。
建好以後,導向到 /cookie 即 ….進入需要驗證的頁面。


/rotues/loginAPI.js

var isLogin=false;
// 進入需要驗證的頁面...
loginAPI.get('/',function(req,res){
  // ...
  var name='guest';
  isLogin=false;
  if(req.signedCookies.firstName && req.signedCookies.lastName){
        name=req.signedCookies.firstName+ ' '+req.signedCookies.lastName;
      isLogin = true;
  }

   res.render('index', { title: 'Express', member:name, logstatus:isLogin });
});

這段程式說明:
一開始預設,所有的登入狀態 isLogin 都是false,預設的登入者是guest。
如果,我們接收到的 cookie 皆存在,則改變 登入者姓名 及 登入狀態。
然而,無論有沒有登入,皆會導到 index.jade 樣版,去做呈現。


/rotues/loginAPI.js

// 登出...
loginAPI.get('/logout', function(req, res) {
    // ...
    res.clearCookie('firstName',{path:'/cookie'});
   res.clearCookie('lastName',{path:'/cookie'});
    return res.redirect('/cookie');
});

這段程式說明:
登出做清理的動作,並返回路由 /cookie


最後,完成的Demo,畫面像這樣:

登入前...
http://ithelp.ithome.com.tw/upload/images/20161224/20103526HOLmcNlBb8.png

登入後...
http://ithelp.ithome.com.tw/upload/images/20161224/20103526lMBpKPLBFZ.png

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


上一篇
Day23 - Cookie & Session
下一篇
Day25 - session 在 express 上的應用 – 登入實作為例
系列文
Node.JS - 30 天入門學習筆記32

尚未有邦友留言

立即登入留言