【学习笔记】cookie、session、token和分布式session
文章目錄
- cookie和Session
- session和token
- cookie和token總結
- 分布式Session
cookie和Session
為什么要有session的出現?
答:是由于網絡中http協議造成的,因為http本身是無狀態協議,這樣,無法確定你的本次請求和上次請求是不是你發送的。如果要進行類似論壇登陸相關的操作,就實現不了了。
Cookie和Session都是客戶端與服務器之間保持狀態的解決方案,具體來說,cookie機制采用的是在客戶端保持狀態的方案,而session機制采用的是在服務器端保持狀態的方案。
1、Cookie 及其相關 API :
Cookie實際上是一小段的文本信息。客戶端請求服務器,如果服務器需要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie,而客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器,服務器檢查該Cookie,以此來辨認用戶狀態。服務器還可以根據需要修改Cookie的內容。
2、Session 及其相關 API:
同樣地,會話狀態也可以保存在服務器端。客戶端請求服務器,如果服務器記錄該用戶狀態,就獲取Session來保存狀態,這時,如果服務器已經為此客戶端創建過session,服務器就按照sessionid把這個session檢索出來使用;如果客戶端請求不包含sessionid,則為此客戶端創建一個session并且生成一個與此session相關聯的sessionid,并將這個sessionid在本次響應中返回給客戶端保存。保存這個sessionid的方式可以采用 cookie機制 ,這樣在交互過程中瀏覽器可以自動的按照規則把這個標識發揮給服務器;若瀏覽器禁用Cookie的話,可以通過 URL重寫機制將sessionid傳回服務器。(?)
瀏覽完了就走了,兩個連接之間是沒有任何聯系的,這也是 HTTP 為無狀態的原因,因為它誕生之初就沒有這個需求。
但隨著交互式 Web 的興起(所謂交互式就是你不光可以瀏覽,還可以登錄,發評論,購物等用戶操作的行為),單純地瀏覽 web 已經無法滿足人們的要求,比如隨著網上購物的興起,需要記錄用戶的購物車記錄,就需要有一個機制記錄每個連接的關系,這樣我們就知道加入購物車的商品到底屬于誰了,于是 Cookie 就誕生了。
Cookie,有時也用其復數形式 Cookies。類型為“小型文本文件”,是某些網站為了辨別用戶身份,進行 Session 跟蹤而儲存在用戶本地終端上的數據(通常經過加密),由用戶客戶端計算機暫時或永久保存的信息 。
???二者存儲位置:
Cookie 是web 服務器發送給瀏覽器的一塊信息,瀏覽器會在本地一個文件中給每個web 服務器存儲cookie以后瀏覽器再給特定的web 服務器發送請求時,同時會發送所有為該服務器存儲的cookie。
Session 是存儲在web 服務器端的一塊信息。session 對象存儲特定用戶會話所需的屬性及配置信息。當用戶在應用程序的 Web 頁之間跳轉時,存儲在 Session 對象中的變量將不會丟失,而是在整個用戶會話中一直存在下去。
Cookie 和session 的不同點:
1、無論客戶端做怎樣的設置,session 都能夠正常工作。當客戶端禁用cookie 時將無法使用cookie。
2、在存儲的數據量方面:session 能夠存儲任意的java 對象,cookie 只能存儲String 類型的對象。
以加入購物車為例,每次瀏覽器請求后 server 都會將本次商品 id 存儲在 Cookie 中返回給客戶端,客戶端會將 Cookie 保存在本地,下一次再將上次保存在本地的 Cookie 傳給 server 就行了,這樣每個 Cookie 都保存著用戶的商品 id,購買記錄也就不會丟失了
cookie圖示:
不難觀察出 cookie 是存儲在 client 的,而 session 保存在 server,sessionId 需要借助 cookie 的傳遞才有意義。
session和token
為什么會有token的出現?
答:首先,session的存儲是需要空間的,其次,session的傳遞一般都是通過cookie來傳遞的,或者url重寫的方式;而token在服務器是可以不需要存儲用戶的信息的,而token的傳遞方式也不限于cookie傳遞,當然,token也是可以保存起來的;
我們知道通過在服務端共享 session 的方式可以完成用戶的身份定位,但是不難發現也有一個小小的瑕疵:搞個校驗機制我還得搭個 redis 集群?大廠確實 redis 用得比較普遍,但對于小廠來說可能它的業務量還未達到用 redis 的程度,所以有沒有其他不用 server 存儲 session 的用戶身份校驗機制呢,這就是下面要介紹的主角:token。
首先請求方輸入自己的用戶名,密碼,然后 server 據此生成 token,客戶端拿到 token 后會保存到本地,之后向 server 請求時在請求頭帶上此 token 即可。
看了上圖會發現存在兩個問題
1、 token 只存儲在瀏覽器中,服務端卻沒有存儲,這樣的話我隨便搞個 token 傳給 server 也行?
答:server 會有一套校驗機制,校驗這個 token 是否合法。
2、怎么不像 session 那樣根據 sessionId 找到 userid 呢,這樣的話怎么知道是哪個用戶?
答:token 本身攜帶 uid 信息
第一個問題,如何校驗 token 呢?我們可以借鑒 HTTPS 的簽名機制來校驗。先來看 jwt token 的組成部分
可以看到 token 主要由三部分組成
當 server 收到瀏覽器傳過來的 token 時,它會首先取出 token 中的 header + payload,根據密鑰生成簽名,然后再與 token 中的簽名比對,如果成功則說明簽名是合法的,即 token 是合法的。而且你會發現 payload 中存有我們的 userId,所以拿到 token 后直接在 payload 中就可獲取 userid,避免了像 session 那樣要從 redis 去取的開銷
注:header, payload 實際上是以 base64 的形式存在的,文中為了描述方便,省去了這一步。
cookie和token總結
Cookie 有哪些局限性?
1、 Cookie 跨站是不能共享的,這樣的話如果你要實現多應用(多系統)的單點登錄(SSO),使用 Cookie 來做需要的話就很困難了(要用比較復雜的 trick 來實現,有興趣的話可以看文末參考鏈接)
畫外音: 所謂單點登錄,是指在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統。
但如果用 token 來實現 SSO 會非常簡單,如下
只要在 header 中的 authorize 字段(或其他自定義)加上 token 即可完成所有跨域站點的認證。
2、 在移動端原生請求是沒有 cookie 之說的,而 sessionid 依賴于 cookie,sessionid 就不能用 cookie 來傳了,如果用 token 的話,由于它是隨著 header 的 authoriize 傳過來的,也就不存在此問題,換句話說token 天生支持移動平臺,可擴展性好
綜上所述,token 具有存儲實現簡單,擴展性好這些特點。
token 有哪些缺點
那有人就問了,既然 token 這么好,那為什么各個大公司幾乎都采用共享 session 的方式呢,可能很多人是第一次聽到 token,token 不香嗎? token 有以下兩點劣勢:
1、 token 太長了
token 是 header, payload 編碼后的樣式,所以一般要比 sessionId 長很多,很有可能超出 cookie 的大小限制(cookie 一般有大小限制的,如 4kb),如果你在 token 中存儲的信息越長,那么 token 本身也會越長,這樣的話由于你每次請求都會帶上 token,對請求來是個不小的負擔
2、 不太安全
網上很多文章說 token 更安全,其實不然,細心的你可能發現了,我們說 token 是存在瀏覽器的,再細問,存在瀏覽器的哪里?既然它太長放在 cookie 里可能導致 cookie 超限,那就只好放在 local storage 里,這樣會造成安全隱患,因為 local storage 這類的本地存儲是可以被 JS 直接讀取的,另外由上文也提到,token 一旦生成無法讓其失效,必須等到其過期才行,這樣的話如果服務端檢測到了一個安全威脅,也無法使相關的 token 失效。
所以 token 更適合一次性的命令認證,設置一個比較短的有效期
分布式Session
引入問題:
如果代碼在一臺應用系統,所有操作都在一臺Tomcat上,沒有什么問題。但是當我們部署多臺系統,配合Nginx的時候會出現用戶登錄的問題
原因
由于 Nginx 使用默認負載均衡策略(輪詢),請求將會按照時間順序逐一分發到后端應用上。
也就是說剛開始我們在 Tomcat1 登錄之后,用戶信息放在 Tomcat1 的 Session 里。過了一會,請求又被 Nginx 分發到了 Tomcat2 上,這時 Tomcat2 上 Session 里還沒有用戶信息,于是又要登錄。這就需要分布式session來解決登陸多次問題
解決分布式session的幾個方案:
1、服務器實現的session 復制或session 共享,這類型的共享session 是和服務器緊密相關的,比如webSphere或JBOSS 在搭建集群時候可以配置實現session 復制或session 共享,但是這種方式有一個致命的缺點,就是不好擴展和移植,比如我們更換服務器,那么就要修改服務器配置。
2、利用成熟的技術做session復制,比如12306使用的gemfire,比如常見的內存數據庫如redis 或memorycache,這類方案雖然比較普適,但是嚴重依賴于第三方,這樣當第三方服務器出現問題的時候,那么將是應用的災難。
3、將session 維護在客戶端,很容易想到就是利用cookie,但是客戶端存在風險,數據不安全,而且可以存放的數據量比較小,所以將session 維護在客戶端還要對session 中的信息加密。
我們實現的方案可以說是第二種方案和第三種方案的合體,可以利用gemfire 實現session 復制共享,還可以將session 維護在redis 中實現session 共享,同時可以將session 維護在客戶端的cookie 中,但是前提是數據要加密。
這三種方式可以迅速切換,而不影響應用正常執行。我們在實踐中,首選gemfire 或者redis 作為session 共享的載體,一旦session 不穩定出現問題的時候,可以緊急切換cookie 維護session 作為備用,不影響應用提供服務。
總結
以上是生活随笔為你收集整理的【学习笔记】cookie、session、token和分布式session的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: springboot中的过滤器、拦截器、
- 下一篇: slf4j的jar包冲突:LoggerF