Session & Cookie
甚麼是 Session?
追蹤同一使用者透過瀏覽器發出的連續請求時,可以製作一組憑證,紀錄設備間的交流,這種機制叫 session。
session 是擁有所有使用者登入紀錄的龐大物件,物件裡都是 key-value pair
, session id(sid)、 value(session_data)。 如同飲料店(伺服器)的會員機制。
存放 session 物件的地方稱為 session store。
甚麼是 Cookie?
cookie,以飲料店的會員卡為例, cookie 為會員卡,通常會員卡放在皮夾中,皮夾即為瀏覽器。
瀏覽器讓伺服器可以把 session id 存在瀏覽器的 cookie 上,使瀏覽器每次對伺服器發送請求時,都帶有cookie資訊,於是伺服器可以透過 cookie 取得 session id。
使用 dev tool 打開 network
打開看伺服器傳給瀏覽器的 Response Headers
,可以發現 set-cookie
,這串特殊編,解譯後會包含session id。
Response Headers
中的 cookie
長串訊息,包含著上次伺服器告訴瀏覽器的通關密碼。 所以這次 request-response
流程, 瀏覽器把這段密碼放到 cookie 傳送給伺服器,於是伺服器就可以辨識出是哪個瀏覽器了。
session 安全性
如果 session id 被盜用,被放到另外一個 cookie 中,將 session id 修改成跟你一樣,就可以在不需要登入的狀況下操作他人帳號。
最普遍防止方法是透過 簽章(signature)
,在伺服器端,開發者設定 密鑰(secret)
, 與要傳送出去的 session id 透過認證演算法整合,產生一組邊碼將之存在 cookie。
於是伺服器端可以使用 secret,還原 session id,如果被惡意篡改,還原會發生錯誤而導致比對無效。
登入功能
實務上稱為 使用者認證(user authentication)
。 建立登入功能,其中簡單的方法是如同註冊功能,檢查資料庫使用者註冊過的資料,使用 User.findOne
查詢資料庫,再 比對密碼是否正確
。
另一種做法使用 Express-session 與 passport,皆為 middleware。
Express-session
建立 session 的 middleware,使用 session(option)。
app.use(session({ |
以上四個參數都是 session middleware 提供的 參數(option)
之一,未來將用以載入,放在修改 app.js 部分。
secret 是可以用來自訂的通關密語,會與資訊做認證演算法整合。
Passport
使用來完成認證功能的 middleware。
Passport Strategies
Passport 須配合認證策略(strategies)
,passport 目前提供超過500種認證策略,讓開法者可以容易將自己產品與各種大型平台服務整合。
設定策略語法(configure strategy)
passport-local 本地策略的策略語法
Serialize 與 deserialize
Passport 的序列化會把 使用者實例(user instance)
轉化為字串存在伺服器端的 session 資料。
反序列化是透過 session 資料,取回擁有 login session 的使用者實例。
// 序列化 |
登入認證實作步驟
- 安裝 passport、passport-local、express-session
- 新增config資料夾,命名 passport.js
- 修改 app.js 使用 passport、 express-session
- 修改使用者路由 routes/user.js
安裝 middleware
npm install passport passport-local express-session |
建立 passport middleware in config/passport.js
關注點分離,新增config資料夾,命名 passport.js,載入 middleware、model,宣告 LocalStrategy 物件, 引入官方語法,定義usernameField 為 email(以 email 代表用戶名稱)。
const LocalStrategy =require('passport-local').Strategy |
修改 app.js
- 載入 express-session、passport middleware
- 使用 app.use 初始化使用 session、passport
- 載入 config/passport.js,設定一個 local variable 儲存 user
2019-6-27
: 新增變數,這個變數的值會從瀏覽器傳到伺服器,讓伺服器知道使用者是否已經登入。
變數: req.local.isAuthenticated
,isAuthenticated 是現成方法, 在設定認證也有相關內容。
const session = require('express-session') |
修改路由 routes/user.js and controller
const express = require('express') |
修改登入頁面
由於使用 handlebars 所以在 template 的地方加入相關語法可以使登出登入按鈕有所變化,而這變化是吃最後在 app.js 中 app.use 有設定到抓取 req.isAuthenticated 的程式碼。
{{#if isAuthenticated}} |