1、HTTP是無狀態協議
HTTP無狀態協議是指該協議對事件的處理過程沒有記憶能力,當后續的步驟需要上一步的信息時,則需要重傳,即需要攜帶上一次的信息。如此,攜帶信息會越來越大,服務器響應會越來越慢。
2、Cookie
2.1、Cookie的原理及工作機制
Cookie是以鍵值對的形式存在的,與URL綁定關聯,保存在客戶端的文件里。
- 當用戶訪問服務器時,服務器可以通過設置
Set-Cookie這個響應頭,將信息返回給客戶端。 - 客戶端瀏覽器會自動讀取這些Cookie信息,並保存在當前域名下的Cookie本地文件當中。
- 當用戶再次訪問該服務器時,瀏覽器也會幫用戶在本地查找與訪問網站頁面相關的Cookie信息。如果Cookie存在且沒有過期的話,瀏覽器會自動將它添加到
request header的Cookie字段中,然后一起發送給服務器。 - 這樣服務器就可以在每次請求的請求頭當中拿到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刷新機制。
