iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 29
0
自我挑戰組

轉職道上的萌芽人生 − 自學程式開發ing系列 第 29

Day 29- 191015學習筆記 Express - Session

  • 分享至 

  • xImage
  •  

提醒:由於看到這系列鐵人訂閱人數漸漸變多,標記一下這些內容是在「非常萌新時期」所寫,更多技術內容請參考我的 Github,歡迎跟我一起討論 ^ ^


今天接著來看看 Express 是如何實作 Session。在前面說過 Express 是以許多 middleware 來運作,而處理 Session 的 middleware 是「express-session」。
這個部分找到一篇不錯文章介紹了 express-session 實作 Session 的方式。


express-session 使用範例

const express = require('express')
const session = require('express-session')
const app = express()
// 會以一個 object 當作參數帶入,在其中設定各種屬性。
app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: true
}))
// 之後即可使用「req.session.key」在 Session 中存取資料

各種屬性的說明:
https://ithelp.ithome.com.tw/upload/images/20191016/20120981ceN9moNjN6.png

  • cookie:儲存 sessionID 的 Cookie 的形式。
  • genid:產生 sessionID 的方式。
  • name:儲存 sessionID 的那個 Cookie 的名稱。
  • resave:即使 Session 沒做變動,是否強制重新儲存進 Store。
  • rolling:是否每次 Request 都強制更換 sessionID。
  • saveUninitialized:是否強制將未初始化的 Session 儲存至 Store。(新產生的 Session)
  • secret:用來認證該 Session 的資料。(必填)
  • store:儲存 Session 的地方。
  • unset:設定是否刪除或保留。('destroy' 或 'keep')

文章中講解了 express-session 實作 Session 的三個重要部分:sessionID 如何產生sessionID 儲存方式session 資訊儲存方式

sessionID 如何產生:

// 可以自訂 產生ID的函式 寫在 genid 屬性(寫在上述的 object),或是用預設的
var generateId = opts.genid || generateSessionId
if (typeof generateId !== 'function') {
    throw new TypeError('genid option must be a function');
  }
// 生成一個 Session 時,同時產生了一個ID
store.generate = function(req){
  req.sessionID = generateId(req);
  req.session = new Session(req);
  req.session.cookie = new Cookie(cookieOptions);
  if (cookieOptions.secure === 'auto') {
    req.session.cookie.secure = issecure(req, trustProxy);
  }};
// 預設產生ID的方式:以 uid-safe 這個library來生成隨機ID
function generateSessionId(sess) {return uid(24);}

sessionID 儲存方式:

將 sessionID 會以以下形式儲存在 cookie
key: connect.sid(或自訂)
value: s:{sessionID}.{hmac-sha256(sessionID, secret)}

var cookie = require('cookie')
var signature = require('cookie-signature')  
/* cookie 中,存放ID的key。可以自訂 寫在「name」或「key」屬性,或是直接使用預設的connect.sid。*/
var name = opts.name || opts.key || 'connect.sid'
var secret = opts.secret
if (secret && !Array.isArray(secret)) {
  secret = [secret];
}  
/* 加入「Set-Cookie」 Header。當 secret 為 Array 時,只有第一項會被放進 Cookie。*/
onHeaders(res, function(){  
  setcookie(res, name, req.sessionID, secrets[0], req.session.cookie.data);
}); 
/* 這裡產生的ID形式,使用了 'cookie-signature' 的 sign 功能,在其後面加了一段鑑別碼,使其無法被串改。 */
function setcookie(res, name, val, secret, options) {
  var signed = 's:' + signature.sign(val, secret);
  var data = cookie.serialize(name, signed, options);
  debug('set-cookie %s', data);
  var prev = res.getHeader('Set-Cookie') || []
  var header = Array.isArray(prev) ? prev.concat(data) : [prev, data]; 
  res.setHeader('Set-Cookie', header)
}

session 資訊儲存方式:

若要使用在產品上,則要另外找地方儲存,例如數據庫(如 MongoDB)、緩存(如 Redis)。

// 可以自訂儲存的方式 寫在 store 屬性,預設為存在記憶體。
var store = opts.store || new MemoryStore()
// 當直接將預設使用在產品時,會提醒你此規格不適合使用在產品。 
if (env === 'production' && store instanceof MemoryStore) {
console.warn(warning);}
/* 預設的方式:在記憶體中建立一個object變數,然後以「key:ID、value:session內容」來儲存。 */
function MemoryStore() {
  Store.call(this)
  this.sessions = Object.create(null)
} 
MemoryStore.prototype.get = function get(sessionId, callback) {
  defer(callback, null, getSession.call(this, sessionId))
} 
MemoryStore.prototype.set = function set(sessionId, session, callback) {
  this.sessions[sessionId] = JSON.stringify(session)
  callback && defer(callback)
}  
function getSession(sessionId) {
  var sess = this.sessions[sessionId] 
  if (!sess) {return} 
  sess = JSON.parse(sess)
  return sess
}

上一篇
Day 28- 191014學習筆記 初窺 Cookie & Session
下一篇
Day 30- 191016學習筆記 passport.js 使用者認證
系列文
轉職道上的萌芽人生 − 自學程式開發ing30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言