Cookie、Session和Token,以及免登陸的實現方案
1、HTTP是無狀態協議
HTTP無狀態協議是指該協議對事件的處理過程沒有記憶能力,當後續的步驟需要上一步的資訊時,則需要重傳,即需要攜帶上一次的資訊。如此,攜帶資訊會越來越大,伺服器響應會越來越慢。
2、Cookie
2.1、Cookie的原理及工作機制
Cookie是以鍵值對的形式存在的,與URL繫結關聯,儲存在客戶端的檔案裡。
- 當用戶訪問伺服器時,伺服器可以通過設定
Set-Cookie
這個響應頭,將資訊返回給客戶端。 - 客戶端瀏覽器會自動讀取這些Cookie資訊,並儲存在當前域名下的Cookie本地檔案當中。
- 當用戶再次訪問該伺服器時,瀏覽器也會幫使用者在本地查詢與訪問網站頁面相關的Cookie資訊。如果Cookie存在且沒有過期的話,瀏覽器會自動將它新增到
request header
- 這樣伺服器就可以在每次請求的請求頭當中拿到Cookie資訊, 然後去做一些邏輯判斷等操作。
每個Set-Cookie 表示一個 Cookie(如果有多個Cookie,需寫多個Set-Cookie),每個屬性都是鍵值對的形式(除了secure),屬性間以分號加空格隔開。格式如下:
Set-Cookie: name1=value[; expires=GMTDate][; domain=domain][; path=path][; secure] Set-Cookie: name2=value[; expires=GMTDate][; domain=domain][; path=path][; secure] Set-Cookie: name3=value[; expires=GMTDate][; domain=domain][; path=path][; secure]
除了在伺服器端設定,還可以在客戶端設定Cookie
document.cookie = "test3=myCookie3; domain=.google.com.hk; expires=Sat, 08 AUG 2021 16:00:00 GMT; secure"
document.cookie = "test4=myCookie4; domain=.google.com.hk; max-age=10800;"
只有name/value可以被髮送至服務端,其餘的引數僅僅是服務端給客戶端的指示或者客戶端自身的約束。
Cookie的缺陷:
- 每個域的Cookie總數是有限的,不同瀏覽器之間各有不同
- 大多數瀏覽器限制Cookie的大小為4KB
- Cookie檔案中可能含有涉密資訊,可能會導致資訊洩露。
2.2、Cookie組成
Name/Value:
該屬性是設定Cookie的名稱及相對應的值,該值通常是保留Cookie中的使用者資訊。而認證Cookie,Value值包括Web伺服器所提供的訪問令牌。
Expires屬性:
該屬性是設定Cookie的生存週期。
- 預設情況下,Cookie是臨時的,關閉瀏覽器,Cookie也會消失。
- 通過設定過期時間Expires屬性,可以有效控制Cookie存活時間,有效期內瀏覽器都可以讀取該Cookie資訊,Cookie到期後會被從Cookie檔案中刪除
Path屬性:
定義了Web站點上可以訪問該Cookie的目錄。比如,設定為"/"表示允許當前域名下的所有路徑都可以使用該Cookie。
Domain屬性:
指定了可以訪問該 Cookie 的 Web 站點或域,預設為當前域。
Secure屬性:
secure是 cookie 的安全標誌,指定是否使用HTTPS安全協議傳送Cookie。
HTTPOnly 屬性 :
用於防止客戶端指令碼通過document.cookie屬性訪問Cookie,有助於保護Cookie不被跨站指令碼攻擊竊取或篡改。
3、Session
3.1、Session的原理及工作機制
Cookie是儲存在客戶端瀏覽器中的,Session是存在服務端伺服器中的。
Session物件可以儲存特定使用者會話所需的所有屬性、配置和資訊。
- Session其實也是通過Cookie實現的。使用者登入後,伺服器將登入資訊儲存在服務端的Session中,並生成一個唯一的session_id,通過Cookie的形式傳送給客戶端。
- 客戶端通過Cookie的機制,每次在訪問伺服器的時候,都會帶上
session_id
。 - 服務端通過Cookie拿到
session_id
後,去Session中找到對應的Session資訊,從而做一些邏輯處理。
3.2、Session缺點
隨著訪問伺服器的使用者數量的增多,伺服器上儲存的Session也日益增多,這對伺服器來說是個巨大的開銷,對於單個伺服器的Web應用匯總,大量的Session會佔用比較多的記憶體。
不僅如此,在分散式系統中,由於負載均衡對請求轉發,這樣就有可能導致同一個使用者的請求分發到不同的伺服器上,會出現獲取不到Session的情況。
以下有三種解決方案:
- 通過
hash_ip
演算法將使用者IP與固定伺服器繫結,該伺服器掛了,請求還是會分發到其他伺服器,依舊獲取不到Session資訊 - 複製Session到所有伺服器,該方法太佔記憶體與頻寬,浪費空間且無法水平擴充套件
- 新增一臺Session伺服器,所有請求先經過該伺服器,如果Session伺服器掛了,那麼所有使用者Session資訊都會丟失
4、Token令牌
4.1、Token的原理和工作機制
通常意義上的token是把session中的內容都放到token中,可以明文形式或者用對稱加密演算法加密(加密金鑰放在伺服器端), 然後再把這些內容做hash簽名(金鑰在伺服器),把內容和其簽名拼接成一個字串(這個就是token) 傳送給客戶端。
客戶端後續請求都帶上這個token,伺服器首先校驗token是否被篡改(根據hash簽名校驗),如果沒被篡改而且token 也沒過期,就把token中的使用者資訊(可能還有許可權資訊等等)拿出來,直接使用,不需要像session一樣去查詢具體使用者資訊。
4.2、Token的優勢
- 無狀態、可擴充套件
在客戶端儲存的token是無狀態的,並且能夠被擴充套件。基於此,負載均衡器將使用者請求傳送到任何一臺伺服器都可以獲取到使用者資訊,而伺服器只需要儲存解析token的祕鑰。 - 安全性
請求中傳送token而不再是傳送cookie能夠防止CSRF(跨站請求偽造)。即使在客戶端使用cookie儲存token,cookie也僅僅是一個儲存機制而不是用於認證。不將資訊儲存在Session中,讓我們少了對session操作。
token是有時效的,一段時間之後使用者需要重新驗證。我們也不一定需要等到token自動失效,token有撤回的操作,通過token revocataion可以使一個特定的token或是一組有相同認證的token無效。 - 可擴充套件性
使用token時,可以提供可選的許可權給第三方應用程式。當用戶想讓另一個應用程式訪問它們的資料,我們可以通過建立自己的API,得出特殊許可權的token。如使用微信登入微博。 - 多平臺跨域
只要使用者有一個通過了驗證的token,資料和資源就能夠在任何域上被請求到。
總結
HTTP請求是無狀態的,就是說第一次和伺服器連線並登陸成功後,第二次請求伺服器仍然不知道當前請求的使用者。Cookie出現就是解決了這個問題,第一次登陸後伺服器返回一些資料(cookie)給瀏覽器,然後瀏覽器儲存在本地,當用戶第二次返回請求的時候,就會把上次請求儲存的cookie資料自動攜帶給伺服器。
- 如果關閉瀏覽器Cookie失效(Cookie就是儲存在記憶體中)
- 如果關閉瀏覽器Cookie不失效(Cookie儲存在磁碟中)
1、Cookie與Session的區別
- cookie資料存放在客戶的瀏覽器上,session資料放在伺服器上。
- cookie不是很安全,別人可以分析存放在本地的cookie並進行cookie欺騙,考慮到安全應當使用session。
- session會在一定時間內儲存在伺服器上,儲存在伺服器的資料會更加的安全,不容易被竊取。當訪問增多,會比較佔用你伺服器的效能與資源,應當使用cookie。
- 單個cookie儲存的資料不能超過4K,很多瀏覽器都限制一個站點最多儲存20個cookie。因此使用cookie只能儲存一些小量的資料。
2、Token和Session的區別
- session翻譯為會話,token翻譯為令牌。
- session和session_id:伺服器會儲存一份,可能儲存到快取/資料庫/檔案,session_id一般是隨機字串,要到伺服器檢索id的有效性。Session通過cookie儲存session_id,然後具體的資料則是儲存在session中。如果使用者已經登入,則伺服器會在cookie中儲存一個session_id,下次再次請求的時候,會把該session_id攜帶上來,伺服器根據session_id在session庫中獲取使用者的session資料。
- token:伺服器不需要記錄任何東西,每次都是一個無狀態的請求,每次都是通過解密來驗證是否合法。
實現免登入方案
- 首先生成token
- 傳送token,兩種方式
- 通過
Set-Cookie
傳送給客戶端,使用者再次請求時,瀏覽器會自動將token帶上傳送給伺服器。 - 通過登入API直接將token返回給客戶端,客戶端通過全域性變數/Storage/Cookie等方式儲存這個token,當用戶再次請求時,客戶端將token值存放在請求頭的
Authorization
中傳送給伺服器。
- 當token中直接儲存了使用者資訊時,直接解密獲取即可;當token只是一個key,真正的資料是存放在Session,Redis 等分散式快取裡時,需要通過token這個key去獲取使用者資訊。從而實現免登陸。
- 為防止token過期,也可以在服務端設定token重新整理機制。