接口中的Cookie,Session,Token


1.無狀態的HTTP協議

以前的Web基本都是文檔的瀏覽而已。既然是瀏覽, 作為服務器, 不需要記錄在某一段時間里都瀏覽了什么文檔, 每次請求都是一個新的HTTP協議,就是請求加響應。不用記錄誰剛剛發了HTTP請求, 每次請求都是全新的。

2.如何管理會話

隨着交互式Web應用的興起, 像在線購物商城,需要登錄的網站等,馬上面臨一個問題,就是要管理回話,記住那些人登錄過系統,哪些人往自己的購物車中放商品,也就是說我必須把每個人區分開。

本文主要講解cookie,session, token 這三種是如何管理會話的;

3.cookie

cookie 是一個非常具體的東西,指的就是瀏覽器里面能永久存儲的一種數據。跟服務器沒啥關系,僅僅是瀏覽器實現的一種數據存儲功能。

cookie由服務器生成,發送給瀏覽器,瀏覽器把cookie以KV形式存儲到某個目錄下的文本文件中,下一次請求同一網站時會把該cookie發送給服務器。由於cookie是存在客戶端上的,所以瀏覽器加入了一些限制確保cookie不會被惡意使用,同時不會占據太多磁盤空間。所以每個域的cookie數量是有限制的。

3.1那么如何設置cookie呢?

客戶端設置

document.cookie = "name=Augus; age=56 "
 復制代碼
  • 客戶端可以設置cookie的一下選項: expires, domain, path, secure(只有在https協議的網頁中, 客戶端設置secure類型cookie才能生效), 但無法設置httpOnly選項

設置cookie => cookie被自動添加到request header中 => 服務端接收到cookie

服務端設置

不管你是請求一個資源文件(如html/js/css/圖片), 還是發送一個ajax請求, 服務端都會返回response.而response header中有一項叫set-cookie, 是服務端專門用來設置cookie的;

  • 一個set-cookie只能設置一個cookie, 當你想設置多個, 需要添加同樣多的set-cookie
  • 服務端可以設置cookie的所有選項: expires, domain, path, secure, HttpOnly

Cookie,SessionStorage,LocalStorage

HTML5提供了兩種本地存儲的方式 sessionStorage 和 localStorage;

img

4.session

4.1.什么是session?

session從字面上講,就是會話。這個就類似你和一個人交談,你怎么知道當時和你交談的是張三而不是李四呢?對方肯定有某種特征(長相等)表明他是張三; session也是類似的道理,服務器要知道當前請求發給自己的是誰。為了做這種區分,服務器就是要給每個客戶端分配不同的"身份標識",然后客戶端每次向服務器發請求的時候,都帶上這個”身份標識“,服務器就知道這個請求來自與誰了。 至於客戶端怎么保存這個”身份標識“,可以有很多方式,對於瀏覽器客戶端,大家都采用cookie的方式。

過程(服務端session + 客戶端 sessionId)

 

session

 

  • 1.用戶向服務器發送用戶名和密碼
  • 2.服務器驗證通過后,在當前對話(session)里面保存相關數據,比如用戶角色, 登陸時間等;
  • 3.服務器向用戶返回一個session_id, 寫入用戶的cookie
  • 4.用戶隨后的每一次請求, 都會通過cookie, 將session_id傳回服務器
  • 5.服務端收到 session_id, 找到前期保存的數據, 由此得知用戶的身份

4.2.存在的問題

擴展性不好

單機當然沒問題, 如果是服務器集群, 或者是跨域的服務導向架構, 這就要求session數據共享,每台服務器都能夠讀取session。

舉例來說, A網站和B網站是同一家公司的關聯服務。現在要求,用戶只要在其中一個網站登錄,再訪問另一個網站就會自動登錄,請問怎么實現?這個問題就是如何實現單點登錄的問題

  1. Nginx ip_hash 策略,服務端使用 Nginx 代理,每個請求按訪問 IP 的 hash 分配,這樣來自同一 IP 固定訪問一個后台服務器,避免了在服務器 A 創建 Session,第二次分發到服務器 B 的現象。
  2. Session復制:任何一個服務器上的 Session 發生改變(增刪改),該節點會把這個 Session 的所有內容序列化,然后廣播給所有其它節點。 SessionCopy
  3. 共享Session:將Session Id 集中存儲到一個地方,所有的機器都來訪問這個地方的數據。這種方案的優點是架構清晰,缺點是工程量比較大。另外,持久層萬一掛了,就會單點失敗; session共享

另一種方案是服務器索性不保存session數據了,所有數據就保存在客戶端,每次請求都發回服務器。這種方案就是接下來要介紹的基於Token的驗證;

5.Token

過程

 

Token

 

  1. 用戶通過用戶名和密碼發送請求
  2. 程序驗證
  3. 程序返回一個簽名的token給客戶端
  4. 客戶端儲存token, 並且每次用每次發送請求
  5. 服務端驗證Token並返回數據

這個方式的技術其實很早就已經有很多實現了,而且還有現成的標准可用,這個標准就是JWT;

6.JWT(JSON Web Token)

數據結構

實際的JWT大概就像下面這樣:

JWT

 

JSON Web Tokens由dot(.)分隔的三個部分組成,它們是:

  • Header(頭部)
  • Payload(負載)
  • Signature(簽名)

因此,JWT通常如下展示:

xxxxx.yyyyy.zzzz

Header(頭部)

Header 是一個 JSON 對象

{
  "alg": "HS256", // 表示簽名的算法,默認是 HMAC SHA256(寫成 HS256) "typ": "JWT" // 表示Token的類型,JWT 令牌統一寫為JWT } 復制代碼

Payload(負載)

Payload 部分也是一個 JSON 對象,用來存放實際需要傳遞的數據

{
  // 7個官方字段 "iss": "a.com", // issuer:簽發人 "exp": "1d", // expiration time: 過期時間 "sub": "test", // subject: 主題 "aud": "xxx", // audience: 受眾 "nbf": "xxx", // Not Before:生效時間 "iat": "xxx", // Issued At: 簽發時間 "jti": "1111", // JWT ID:編號 // 可以定義私有字段 "name": "John Doe", "admin": true } 復制代碼

JWT 默認是不加密的,任何人都可以讀到,所以不要把秘密信息放在這個部分。

Signature(簽名)

Signature 是對前兩部分的簽名,防止數據被篡改。

首先,需要指定一個密鑰(secret)。這個密鑰只有服務器才知道,不能泄露給用戶。然后,使用Header里面指定的簽名算法(默認是 HMAC SHA256),按照下面的公式產生簽名。

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret) 復制代碼

算出簽名后,把 Header、Payload、Signature 三個部分拼成一個字符串,每個部分之間用"點"(.)分隔,就可以返回給用戶。

JWT = Base64(Header) + "." + Base64(Payload) + "." + $Signature 復制代碼

如何保證安全?

  • 發送JWT要使用HTTPS;不使用HTTPS發送的時候,JWT里不要寫入秘密數據
  • JWT的payload中要設置expire時間

使用方式

客戶端收到服務器返回的 JWT,可以儲存在 Cookie 里面,也可以儲存在 localStorage。此后,客戶端每次與服務端通信,都要帶上這個JWT。你可以把它放在Cookie里面自動發送,但是這樣不能跨域,所以更好的做法是放在HTTP請求的頭信息 Authorization 字段里面。

Authorization: Bearer <token>
復制代碼

另一種做法是, 跨域的時候, JWT就放在POST請求的數據體里。

JWT 的作用

JWT最開始的初衷是為了實現授權和身份認證作用的,可以實現無狀態,分布式的Web應用授權。大致實現的流程如下

JWT

 

  1. 客戶端需要攜帶用戶名/密碼等可證明身份的的內容去授權服務器獲取JWT信息;
  2. 每次服務都攜帶該Token內容與Web服務器進行交互,由業務服務器來驗證Token是否是授權發放的有效Token,來驗證當前業務是否請求合法。

這里需要注意:不是每次請求都要申請一次Token,這是需要注意,如果不是對於安全性要求的情況,不建議每次都申請,因為會增加業務耗時;比如只在登陸時申請,然后使用JWT的過期時間或其他手段來保證JWT的有效性;

Acesss Token,Refresh Token

JWT最大的優勢是服務器不再需要存儲Session,使得服務器認證鑒權業務可以方便擴展。這也是JWT最大的缺點由於服務器不需要存儲Session狀態,因此使用過程中無法廢棄某個Token,或者更改Token的權限。也就是說一旦JWT簽發了,到期之前就會始終有效。 我們可以基於上面提到的問題做一些改進。

前面講的Token,都是Acesss Token,也就是訪問資源接口時所需要的Token,還有另外一種Token,Refresh Token。一般情況下,Refresh Token的有效期會比較長。而Access Token的有效期比較短,當Acesss Token由於過期而失效時,使用Refresh Token就可以獲取到新的Token,如果Refresh Token也失效了,用戶就只能重新登錄了。Refresh Token及過期時間是存儲在服務器的數據庫中,只有在申請新的Acesss Token時才會驗證,不會對業務接口響應時間造成影響,也不需要向Session一樣一直保持在內存中以應對大量的請求。

 

Refresh Token

6.區別

Cookie和Session的區別

  1. 存儲位置不同: cookie數據存放在客戶的瀏覽器上,session數據放在服務器上
  2. 隱私策略不同:cookie不是很安全, 別人可以分析存放在本地的cookie並進行cookie欺騙,考慮到安全應當使用session
  3. session會在一定時間內保存在服務器上。當訪問增多,就會比較占用你服務器的性能,考慮到減輕服務器性能方面,應當使用cookie
  4. 存儲大小不同: 單個cookie保存的數據不能超過4k, 很多瀏覽器都限制一個站點最多保存20個cookie

一般建議: 將登陸信息等重要信息存放為session, 其他信息如果需要保留,可以放在cookie中

Token和Session的區別

Session是一種HTTP儲存機制, 為無狀態的HTTP提供持久機制; Token就是令牌, 比如你授權(登錄)一個程序時,它就是個依據,判斷你是否已經授權該軟件;

Session和Token並不矛盾,作為身份認證Token安全性比Session好,因為每一個請求都有簽名還能防止監聽以及重放攻擊,而Session就必須依賴鏈路層來保障通訊安全了。如上所說,如果你需要實現有狀態的回話,仍然可以增加Session來在服務端保存一些狀態。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM