cookie,session,token的區別

cookie,session,token它們本質上不是同一個東西。但是都跟維持狀態信息有關係。

什麼是狀態信息呢?

我來用一個登錄來個大家講解。

如果我們登錄以後,希望後續的所有的頁面都維持登錄的狀態,那我們就需要用剛剛講到的cookie,session,token來進行實現。

那麼如果沒有使用上面的任何一種技術,我們要維持用戶的登錄狀態信息,是非常麻煩的

我給你舉個例子,就比如說當發起一個登錄請求,把用戶名,密碼傳到服務端。服務端進行鑑權(認證),判斷用戶名密碼是否正確,正確的話需要再把用戶名密碼傳到前端,

以維持登錄的狀態信息,那麼後續請求任何頁面,我們都需要帶上用戶名密碼。那麼這樣做的話毫無疑問,既不安全又麻煩。 

 

 我們就可以用cookie來解決。同樣的前端發起登錄請求,會在服務端進行用戶名密碼認證,如果認證成功,會響應用戶名到前端,前端把用戶名進行保存(到cookie),

保存之後,cookie是保存在瀏覽器這一端,那麼後續就登錄成功,後續所有請求都會自動帶上cookie,這樣就維持了用戶的登錄狀態。

那如果只用cookie來存儲狀態信息呢?其實是會有很多問題的。

1.安全風險:有被篡改的風險。

2.容量限制:4kb。

3.可用限制:用戶可能禁用。

因爲cookie是存儲在客戶端的,也就是存儲在瀏覽器,那用戶呢,他是可以去篡改,就像剛剛直接把用戶名存儲在了cookie,那登錄成功之後呢,它每次的請求都會帶上cookie,

以證明當前已經登錄,那麼在服務端呢,就會根據cookie當中的這個用戶名,來獲取當前的登錄信息,那麼用戶他是可以把當前的cookie當中的用戶名給篡改掉,改成其他的用戶,

那麼對於服務端來說,我只會根據你cookie的信息來獲取當前登錄的用戶,所以一旦被篡改的話,是有非常大的安全風險。

當然可以進行加密,但是一旦用戶知道我們的加密規則呢?也是可以進行篡改的。

那麼第二個問題就是它的容量有限,默認的大小是4kb,當然也可以通過瀏覽器進行修改。以及用戶他可以通過瀏覽器把cookie給禁掉。所以不能完全依賴cookie保持這個登錄狀態。

 

那麼進而我們就可以通過session,那麼session的使用過程是這樣的。

當前端發起登錄請求,會把用戶名密碼傳到後端,後端驗證,如果認證成功,可以往session當中存入當前用戶的信息,然後進行響應,

響應的時候會在響應頭裏面存入一個叫做set-cookie的屬性,然後再把當前session的唯一id放在屬性當中,前端會自動在cookie中存入當前的sessionId,那麼下次登錄成功以後,下一次請求就會自動在請求頭

當中設置cookie信息。服務端拿到cookie當中的session id就可以得到當前這次請求所對應的session信息了,那麼就可以獲取到當前登錄的用戶信息,以維持當前的登錄狀態。

那麼在這個過程中,session它的使用其實是非常方便的,我們只需要在後端存入當前用戶的信息,並且不僅僅限於字符串,我們可以存入整個的User對象,那麼下次獲取是非常方便的。

那麼我們的服務器比如tomcat,它會自動在響應頭裏面存入set-cookie的屬性以及當前session的唯一ID,這個我們不需要去管。然後瀏覽器發現你的響應頭裏面有set-cookie屬性,它就會自動的存入session id到cookie中。

我們不需要在瀏覽器這一端在前端去調用setCookie()方法,響應頭當中的set-cookie命令它會自動幫我們存儲,並且瀏覽器下一次請求也會把cookie傳到服務端,所以整個過程是自動完成,我們只管往session中存數據即可。

用起來是非常方便的。當然session同樣有一些問題。

1.佔用服務器資源。

2.擴展性差(分佈式集羣)。

3.依然需要依賴cookie,跨域限制。

 如果在高併發情況下,是會比較佔用服務器內存資源的。以及它的擴展性比較差,對跨域的限制,這兩點怎麼理解呢?比如我們的後端它的壓力比較大,此時我們可能就會進行集羣部署,假如前端發起登錄請求,

我們往session中存入當前的用戶信息,只會存在一臺服務器,那麼其他服務器並沒有當前的用戶登錄信息,那麼集羣之後負載均衡,有可能下一次的請求就會打到其他的服務器上面,那麼就會判定你當前並沒有登錄。

所以在集羣情況下,session它是不支持的,以及呢,我們現在基本都是前後端分離的架構,特別是在移動互聯網盛行的情況下,我們還會有移動端H5,還會有小程序,安卓端,蘋果端,它們都會有各自的端口域名,

這個時候前端再請求後端就會發生跨域,跨域的情況下,cookie默認是無法進行傳遞的,我們需要在後端設置允許跨域,還需要在前端單獨的去設置,允許跨域的cookie傳遞,總之呢,跨域進行傳遞cookie非常麻煩。

所以在集羣環境,以及前後端分離的架構下,session已經不再適用

 

那麼其實我們就可以通過token來進行改造了,token說白了就是一個祕鑰字符串。我們怎麼去進行加密呢?

其實jwt提供了規範,json web token,說白了就是通過json來進行傳遞加密後的字符串。

jwt的整個使用過程,同樣的前端發起登錄請求,後端會進行認證,認證成功之後會創建一個jwt的字符串,它會包含三段信息,然後會把創建好的jwt返回給前端,前端拿到jwt的token如果想要數據的載體,只要進行分割,分割之後

拿到第二段,因爲第二段保存的是數據的載體,拿到之後通過base64方式進行解碼即可。

那麼登錄成功之後,後續的請求只需要請求頭當中設置一個跟後端約定的一個屬性,然後再把響應的jwt的token傳入到後端,那麼後端拿到這個token就會進行jwt解密,然後驗證signature, 如果校驗成功信息沒有被篡改,

就會放行,正常的進行響應。所以說使用jwt,我們不需要依賴後端的任何存儲,也不需要依賴前端的任何存儲,它就是一個加密之後的字符串而已,對於我們現在的集羣以及前後端分離的架構這樣的環境使用起來非常方便。

 

注意:

jwt無法做到主動退出登錄。

雖然我們使用JWT已經很方便了,但是有一個很嚴重的問題就是,我們沒辦法像Session那樣去踢用戶下線,什麼意思呢?我們之前可以使用退出登錄接口直接退出,用戶Session中的驗證信息也會被銷燬,但是現在是無狀態的,用戶來管理Token令牌,服務端只認Token是否合法,那這個時候該怎麼讓用戶正確退出登錄呢?

jwt有其自己的適用場景,任何時候都不應該首要考慮JWT。你使用JWT的時候,應該是你有明確需要JWT特性的時候。

傳統的Token方案,其實就是Session的管理方案。Session管理的方式是什麼?無非就是給你一個sessionId,然後服務器向這個SessionId的內存裏存放用戶當前的登陸信息以及相關數據。

所謂的Redis+token。無非也就是給這個基礎業務包了一層殼。Session說是不安全,給你頒發了一個名叫token的玩意。傳統session不支持分佈式,於是引入了redis。(其實說實話,分佈式Session用Redis實現也是這麼個道理。

就這麼個最傳統的token方案,已經足以解決99%的業務場景

單個token+redis+自動續期與雙token+redis方案對比:
 

  

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章