基本概念及區分
單點登陸 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 的內容。修改權限什麼的。
-
安全性算法
-
問題數據庫
- 每次請求都攜帶,浪費帶寬。
- 容量小
- 數據可見
- 數據不安全,能夠被篡改。僞造請求。
session 會話機制
JWT(json web token) 會話機制
-
經常使用數據保存在【客戶端】
- JWT 是一個數據結構,不像 cookie 是一種技術,數據能夠保存在 cookie 中,也能夠 localStorage 中。
-
組成
- 協議
- 內容體,規定爲 json 形式
- 前二者加上祕鑰的 hash 值,防止僞造
-
特色
- 數據可見,但不可僞造。
- 後端拿到數據後直接使用,無需 IO 查詢
- 祕鑰很重要,泄露了就能夠僞造全部人。
- 易於擴容,單點登陸,只需查數據有沒有被篡改過就行。
-
安全性
-
問題
會話保持機制的缺點及定位
僅靠會話保持機制沒法解決如下問題
惟一登陸問題
- 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 的時候,須要重寫該項的全部屬性(即便未發生變化,也要寫上去),不然將識別爲獨立的兩項。不能成功清除會話標識。
- 若是未成功清除,那應該是屬性項未寫全。