Blazor和Vue對比學習(進階2.2.4):狀態管理之持久化保存(2),Cookie/Session/jwt

註:本節涉及到前後端,這個系列的對比學習,還是專註在前端VueBlazor技術,所以就不擼碼了,下面主要學習概念。

 

我們知道,Http是無狀態協議,客戶端請求服務端,認證一次後,如果再次請求,又要重新認證,因為對服務端來說,客戶端的每次請求都是無差別的!另外,服務端的授權體系,一般使用基於RBAC角色權限模型。角色信息,我們可以在客戶端每次請求都,都查詢一次,但這樣比較消耗資源。最好的方式,是客戶端第一次請求時,就將角色傳給客戶端,之後客戶端每次請求,直接攜帶角色信息。而這些問題,都需要使用Cookie、Session或者jwt來解決。

 

1、先說Cookie。下圖為Cookie在客戶端與服務端的應用邏輯圖。

 

 

如上圖所示:

  • 客戶端首次請求服務器時,攜帶參數(如用戶名和密碼),服務器根據參數判斷是否合法。如合法,則在Response中頒發Cookies,如在.NET中,寫入Cookie,【Response.Cookies[name].value = functionMC;Response.Cookies[name].Expires=DateTime.Now.AddDays(1);】,其中Expires屬性,為服務端設置的過期時間。
  • 客戶端收到服務器的Response後,將Cookie以健值對的方式保存到瀏覽器中,如使用js直接操作DOM,【document.Cookie=”username=John Doe; expires=Thu, 18 Dec 2043 12:00:00 GMT”;】,客戶端也可以設置過期時間。如不設置,保存在內存中,瀏覽器關閉時自動清除;如設置,則保存在本地硬盤中,到期後自動清除。
  • 之後,客戶端每次訪問服務器,都會在請求頭中攜帶相應站點的Cookie。服務端就可以讀取Cookie,如在.NET中,讀取Cookie,【string name = Request.Cookies[name].value
  • Cookie在安全性方面,易出現Cookie劫持和欺騙,大小和數量方面也受限制。所以在Cookie之後,出現了Session

 

2、Session。下圖為Session在客戶端與服務端的應用邏輯圖

 

如上圖所示

  • 客戶端首次訪問服務器後,判斷是否合法,如果合法,則在服務器的緩存中建立一個鍵值對,鍵為SessionID,同時將SessionID作為Cookie返回給客戶端。客戶端再次請求時,請求頭攜帶SessionID,服務端根據SessionID,查找緩存信息,根據緩存信息進行處理。
  • 使用Session後,客戶端與服務端之間只傳遞SessionID,更多信息在服務端緩存中,這樣可以保存更多信息。Session可以設置有效期,也可以不設置。如不設置,則只在當前會話中有效,客戶端關閉後就失效,這樣也更安全。
  • Session本身的含義,指客戶端與服務端之間的會話,背後實質指的是一種服務器緩存,如果請求不是很多,效率還是很高的
  • Session可以有效利用服務端資源,不受客戶端限制,安全性更好。但是,當客戶端的並發請求比較多時,會很占服務器內存。如果是分佈式,不同的Session存儲在不同的服務器之間,而客戶端每次請求的路徑是隨配的,要解決分佈式,我們就需要在每台服務器之間同步SessionID和緩存信息。最後,SessionID還是依賴於CookieCookie的跨域、單點登陸難等問題,它也一樣有。所以,token的方案開始出現,它是目前最主流的方案,而其中最重要的標準,就是jwt

 

 

3、jwt。下圖為token/jwt在客戶端和服務端的應用邏輯圖

 

如上圖所示,jwt重新將信息保存在了客戶端,節省了服務端資源,也沒有分佈式的問題,同時在靈活性和安全性方面有了質的提升。

  • 靈活性方面:不再限於Cookie,可以保存到本地的StorageIndexedDB,甚至於遠程數據庫里,更加的自由。同時,它以JSON加密形式保存在客戶端的,是跨語言的,原則上任何web形式都支持。
  • 安全性方面:可以說有了質的提升,這才是jwt的核心。首先它可以完全不依賴於Cookie,它沒有跨域、單點登陸等問題;其次,它將加密和解密的過程,放在了服務器上,即使信息被截獲,也無法篡改。
  • 更好的支持分佈式:在Session方案中,我們需要在每個服務器都進行緩存同步。而jwt中,我們只要在每個服務器都拷備一份密鑰即可,或者可以將密鑰統一保存到一個Redis服務器中,每個服務器統一向Redis請求密鑰,這樣連拷貝密鑰的工作也可省去

 

下面簡單說明一下jwt的構成、生成、加密和解密過程:

  • jwtHeaderPlayloadSignature三部分組成,以符號「.」連接成字符串。其中Header是一個json對象的Base64編碼,主要有簽名的算法信息;Playload也是一個json對象的Base64編碼,這是傳輸的主體內容,比如用戶角色、所在部門等信息都可以存放在裏面。我們知道Base64不具有加密能力,可以說HeaderPlayload是明文傳輸的,在Playload裏面,千萬不能放敏感信息。而Signature才是jwt安全體系的核心
  • jwt是在服務端生成的,我們定義好HeaderPlayload後,在服務端我們有一個密鑰Secret,這個密鑰是一個沒有規律的字符串。我們使用Header里的哈希算法,加上密鑰、HeaderPlayload,就可以算出簽名SignatureSignature是不可匿的,無法破解,破解也沒意義。
  • 客戶端再次請求時,服務端獲得請求頭攜帶的jwt後,取出HeaderPlayloadSignature(A)。對Header進行Base64解碼,獲取其中的哈希算法,然後重新使用這個哈希算法,加上密鑰、HeaderPlayload重新算出一個簽名Signature(B),然後比對Signature(A)Signature(B)是否一致,如果一致,則請求是合法的,服務端放行,並使用Playload中的信息進行計算處理。
  • 服務端的密鑰Secret,是計算簽名的安全核心,一定要保存好,最好定期更新。