【達生科技】會話機制及其架構設計探討

基本概念及區分

單點登陸 SSO(Single Sign On)

  • 在一個多系統共存的環境下,用戶在一處登陸後,就不用在其餘系統中登陸,也就是用戶的一次登陸能獲得其餘全部系統的信任。
  • 單點登陸在大型網站裏使用得很是頻繁,例如像阿里巴巴這樣的網站,在網站的背後是成百上千的子系統,

惟一登錄

  • 也叫「單用戶登陸」,是指一個帳號同時只能在一個設備上登陸使用。
  • 經常使用於會員系統網站,如會員視頻網站。不能夠多人同時使用一個帳號登陸使用。

http 是無狀態的協議

  • 每一個 http 請求之間都相互不認識,若是不作程序上的處理,沒法區分兩個 http 請求是否來至於同一個用戶。

會話

  • 瀏覽器與服務器能夠相互識別的對話的過程,
  • 因爲 http 是無狀態的協議,在不作程序上的處理狀況下,每一個 http 請求都是獨立的會話。

會話保持

  • 爲了解決 http 無狀態致使的會話時間過短問題。提出的解決方法,即想辦法在不一樣的 http 請求中能識別是否來至於同一我的。
  • 一次會話保持:從瀏覽器訪問該域名下的頁面開始,到瀏覽器關閉該域名下的全部頁面結束。標識爲一個會話。(不用在乎「一次會話」這個名字,筆者以爲這個名字起得並很差。名詞意義並不等於實際意思,就像「單點登陸」同樣,誤導人)
  • 時間段會話保持:即以特定時間段內做爲一個會話。能夠是相對最後一次使用的時間,也能夠是絕對時間。

會話保持機制

  • 即實現「會話保持」的具體方案,具體有多種方案,如 cookie 會話機制,session 會話機制,jwt 會話機制等。

cookie

  • 一種技術,每次發送請求都會攜帶該數據,有本身的實體,原子性的,不可分割的。

cookie 會話機制

  • 是會話保持機制的一種具體實現方案,cookie 的一種應用。
  • 指明瞭使用的技術就是 cookie

sessionStorage

  • 至關於前端的數據庫,數據在「一次會話保持」內有效。
  • 一種技術,前端數據存儲的一種技術,有本身的實體。

session 會話機制

  • 是會話保持機制的一種具體實現方案,須要使用「客戶端標識」及「服務端存儲」
  • 未指明具體使用那些技術。只介紹告終構。

session

  • 本來只是「會話」對應的英文名,不存在實體,也不是一種應用。
  • 在前端中,前端

    • session 存儲空間的意義,變成了「sessionStorage」的簡稱,「數據存到 session 中」意味着「數據存到 sessionStorage 中」。
    • session 時間範圍的意義,變成了「一次會話保持」的時間段。從瀏覽器訪問到瀏覽器結束。
  • 在後端中mysql

    • session 存儲空間的意義,變成了「session 會話機制」中的「服務端存儲」。存在session,意味着存在「服務端存儲」中(多是內存,也多是數據庫)
    • session 時間範圍的意義,變成了「會話保持」的時間段,多是「一次會話保持」時間段,也多是「時間段會話保持」,看具體配置。但更常見的是「時間段會話保持」的時間範圍。

會話保持機制具體方案介紹

cookie 會話機制

  • 經常使用數據直接保存在【客戶端】web

    • 經常使用數據,即在編程中常常用到的數據,如當前用戶的 userId,userName等。
  • 特色redis

    • 數據可見。
    • 每次請求都自動攜帶上。
    • 後端拿到數據後直接使用,無需轉換。
    • 數據能夠直接僞造。利用 Node 僞造一個 http 請求,並修改 cookie 的內容。修改權限什麼的。
  • 安全性算法

    • csrf(跨域僞造請求攻擊),登陸 A 網站,訪問 B 網站(B 網站私自調用 A 網站接口,自動帶上了cookie,執行了操做)sql

      • 服務端校驗請求頭 Referer(指明當前流量的來源參考頁面),即當前頁面的 URL,從而校驗域名。
    • 可能有 xss (跨站腳本漏洞),往你的網站中注入 js 代碼。chrome

      • 經過設置 HttpOnly=true,禁止 JS 獲取或操做 cookie 解決
  • 問題數據庫

    • 每次請求都攜帶,浪費帶寬。
    • 容量小
    • 數據可見
    • 數據不安全,能夠被篡改。僞造請求。

session 會話機制

  • 經常使用數據保存在【服務端】,標識符保存在【客戶端】編程

    • 當前用戶的 userId,userName等經常使用數據保存在服務端
    • 每一個用戶對應一個隨機字符串(即與信息無關的標識符),該字符串保存在【客戶端】
    • 每次通信,客戶端傳遞「標識符」,服務端經過「標識符」找到「經常使用數據」
    • 「經常使用數據」和「標識符」分別怎麼保存json

      • 「經常使用數據」的客戶端存儲介質:內存變量,redis(緩存數據庫),mysql(常駐數據庫)
      • 「標識符」默認是 cookie,也能夠經過前端配合,存儲在 localStorage 中。若是將數據存儲在一個叫 token 的響應頭中,就變成了咱們熟悉的 token 校驗。但實際上 token 並非解決方案,這只是變量名。不能說是 token 解決方案。
  • 特色

    • 數據對外不可見
    • 每次接口請求,都須要經歷一次從「標識符」到「經常使用數據」的查詢
    • 不利於擴容 和 單點登陸。須要在多個服務進程間同步「經常使用數據」
  • 安全性

    • csrf(跨域僞造請求攻擊)

      • localStorage 不存在,使用 cookie 可杜絕,
    • 可能有 xss (跨站腳本漏洞),往你的網站中注入 js 代碼。

      • 使用 localStorage 不可杜絕,cookie 可杜絕
  • 問題

    • 不利於擴容,數據須要在多進程間同步。
    • 使用內存存儲,當數據量實在太大時,容量溢出。
    • 使用數據庫存儲,每次查詢都消耗 IO,響應速度慢。

JWT(json web token) 會話機制

  • 經常使用數據保存在【客戶端】

    • JWT 是一個數據結構,不像 cookie 是一種技術,數據能夠保存在 cookie 中,也能夠 localStorage 中。
  • 組成

    • 協議
    • 內容體,規定爲 json 形式
    • 前二者加上祕鑰的 hash 值,防止僞造
  • 特色

    • 數據可見,但不可僞造。
    • 後端拿到數據後直接使用,無需 IO 查詢
    • 祕鑰很重要,泄露了就能夠僞造全部人。
    • 易於擴容,單點登陸,只需查數據有沒有被篡改過就行。
  • 安全性

    • csrf(跨域僞造請求攻擊)

      • localStorage 不存在,使用 cookie 可杜絕,
    • 可能有 xss (跨站腳本漏洞),往你的網站中注入 js 代碼。

      • 使用 localStorage 不可杜絕,cookie 可杜絕
  • 問題

    • 數據可見

會話保持機制的缺點及定位

僅靠會話保持機制沒法解決如下問題

惟一登陸問題

  • A B 使用同一個帳號。A 登陸,有了 sessionIdA。B 再登陸,有 sessionIdB。
  • 在不作額外判斷的情形下,實現不了使 sessionIdA 失效的功能。
  • 只能將 sessionId 存儲在數據庫中,每次操做時,都查詢 sessionId 的有效性。

權限校驗問題

  • 當 A 登陸,有了 sessionIdA 後。修改 A 用戶的權限,甚至刪除 A 用戶。
  • 這時 sessionIdA 依然有效。沒法限制其使用。
  • 當前流行的後端框架都沒有操做特定 session 的功能,只能操做當前 session。
  • 只能每次都查數據庫。但既然每次都查數據庫,是否是也意味着,將數據存在 session 中沒有意義?反正都是查數據庫,我直接從數據庫拿就好。

會話保持機制的定位

  • 會話數據:數據可丟失,無需復現,兩會話的數據差別不會產生衝突。
  • 數據庫長期數據:可溯源,可重現,有惟一性。
  • 應該只保存與用戶信息無關的數據,如「提交臨時表單」等,不須要固話到數據庫的臨時數據。
  • 由於會話只是記錄當前通信的信息,同一個帳號,可能同時有多個會話。若是將用戶相關信息長期數據存儲在會話中,則可能會致使各個會話間的數據不統一。
會話保持機制及數據緩存架構設計
  • 會話保存層

    • 保存 userId,設置終端設備信息,系統類別等固化信息
    • userId 不會被改變
    • 終端設備信息,如 useragent,用於記錄瀏覽器類型等數據採集
    • 系統識別號,譬如「後臺管理系統」和「移動端應用」,「移動端應用」的 session 不該該能操做 「後臺管理系統」。譬如我複製 sessionId,調用「後臺管理系統」
  • redis 數據緩存層,

    • 經過 userId 組織數據。實現多個 session 的用戶數據同步問題。
    • 用戶權限,校驗每一個接口的調用權限,經過。
    • 最後登陸的 sessionId,實現「惟一登陸」。
    • 開發經常使用數據。
  • mysql 數據層

    • 固化數據,當對 mysql 數據進行修改時,如修改權限,須要將數據同步到 redis 中。
    • 當用戶登陸時,生成 redis 的 userId 與 session 映射關係數據。
    • mysql 和 redis 的用戶數據是同步,同樣的。redis 的存在只是爲了對特定數據進行優化查詢。如每一個接口都要校驗的用戶權限。
會話保持機制的選擇
  • cookie 會話保持機制

    • 自己不帶加密功能,容易被僞造。不建議。
  • session 會話保持機制

    • 從 sessionId 到 session 信息。須要通過一次隱射查詢。
  • jwt 會話保持機制

    • 多了一次 hash 算法校驗,但 計算耗時 對 IO 耗時來講不值一提。
    • 數據可見,但數據不敏感,影響不大。
    • 對比 session,減小一次查詢。
    • 但因爲數據存貯在客戶端,每次調接口,都須要傳輸,雖然量少,但仍是會浪費帶寬。
  • 因此最後在 session 與 jwt 中作對比

    • 犧牲查詢,仍是犧牲帶寬
    • 筆者傾向於後者。應爲帶寬的影響是分佈在每一個用戶上的,不會產生累計效應,不影響服務器速度。
    • 而前者的壓力徹底集中在服務器中,用戶基數大時,對服務器的影響不可忽略。
客戶端主動解除會話

據上述會話保持機制可知,保持會話,須要先後兩端共同支持(cookie是瀏覽器默認支持)。故雙方都可主動放棄維持該會話

  • 保存在 localStorage

    • 直接調用 localStorage.removeItem('key') 便可清除會話標識。從新登陸。
  • 保存在 cookie

    • 特殊狀況,若後端響應頭設置 HttpOnly=true,禁止 JS 獲取或操做 cookie 解決。

      • 則前端沒法經過代碼操做 cookie,沒法經過程序清除登陸狀態。
      • 但在開發中,可經過客戶端主動清除。如使用 chrome 瀏覽器,調起控制檯清除 cookie。
    • 若未設置 HttpOnly=true,則可經過 JS 清除 cookie。

      function setCookie(name, value) {
        var exp = new Date();
        exp.setTime(exp.getTime() - 1);
        document.cookie = name + "=" + escape(value) + `;expires=${exp.toGMTString()};path=/`;
      }
      
      setCookie('PHPSESSID', '')
      • JS 沒有相似 removeItem,同樣的 cookie.removeItem 函數。只可經過設置 cookie 的過時時間,讓客戶端主動幫你清除。
      • 須要注意的是,在重寫某項 cookie 的時候,須要重寫該項的全部屬性(即便未發生變化,也要寫上去),不然將識別爲獨立的兩項。不能成功清除會話標識。
      • 若是未成功清除,那應該是屬性項未寫全。
相關文章
相關標籤/搜索