發展史:
1. 早期的WEB基本上就是文檔的瀏覽而已,服務器不需要記錄誰在某個時間都瀏覽了什么文檔,每次請求都是全新的HTTP協議。
2. 隨着交互式WEB應用的興起,例如在線購物網站,需要登錄的網站等,則需要對會話進行管理,分別記錄每個用戶放入購物車中的商品,記錄用戶的登陸信息等,因為HTTP請求是無狀態的,即:用戶第一次發起請求與服務器建立連接並登錄成功后,為了避免每次打開一個頁面都需要登錄一下,由此就出現了 cookie,Session。
3.使用Session的話,服務器要保存每個人的sessionId(客戶端頻繁的發出請求數據,服務端頻繁的去數據庫查詢數據進行對比)當用戶訪問量增多的時占用空間,就越多耗費服務器性能。
—> 那么用多台服務器搭建集群來提高性能呢?當用戶發送請求時無法在多台之間共享Session。
—> 那么再通過負載均衡將sessionId在多台之間互相復制呢?這樣服務器性能也是個問題。
—> 那么使用Memcached把sessionId集中存儲到一個地方,所有的機器都來訪問這個地方的數據呢?如果負責sessionId的機器掛了,則所有人都得重新登陸了。
—> 那么再為這個負責sessionId的機器也做成集群,增加可靠性呢?。。。不管如何session還是個負擔。
4.Session在大量訪問時給服務器造成壓力,在這種情況下,Token應用而生。
一、Cookie:是服務器在本地機器上存儲的小段文本並隨每一個請求發送至同一個服務器,是一種在客戶端保存用戶信息的一種機制。
網絡服務器用HTTP頭向客戶端發送cookies,在客戶終端,瀏覽器解析這些cookies並將它們保存為一個本地文件,它會自動將同一服務器的任何請求縛上這些cookies 。
Cookie是由網絡服務器通過HTTP頭發送到客戶端瀏覽器,瀏覽器把cookie以key-value的形式保存到某個目錄下的文本文件中,下一次請求同一網站時會把該cookie發送給服務器。
瀏覽器為了確保cookie不被惡意使用,隨意對cookie由一些限制:不會占用太多磁盤空間,只存儲少量的數據(不同的瀏覽器有不同的存儲大小,但一般不超過4KB,很多瀏覽器都限制一個站點最多保存20個cookie)。
Cookie 的組成:
名稱(key)、值(value)、有效域(domain)、路徑(域的路徑,一般設置為全局:"\")、
失效時間:(若不設置則表示這個cookie的生命期為瀏覽器會話期間,關閉瀏覽器窗口,cookie就消失。這種生命期為瀏覽器會話期的cookie被稱為會話cookie。會話cookie一般不存儲在硬盤上而是保存在內存里,當然這種行為並不是規范規定的。若設置了過期時間,瀏覽器就會把cookie保存到硬盤上,關閉后再次打開瀏覽器,這些cookie仍然有效直到超過設定的過期時間。存儲在硬盤上的cookie可以在不同的瀏覽器進程間共享,比如兩個IE窗口。而對於保存在內存里的cookie,不同的瀏覽器有不同的處理方式)、
安全標志:(指定后,cookie只有在使用SSL連接時才發送到服務器(HTTPS))。
輸入用戶名密碼登錄網站后,之后再打開網站很多情況下就直接進去了,這個時候用到的一個機制就是Cookie。
二、Session(會話) :存儲在服務端的一個數據結構。
Session 是一種HTTP存儲機制,目的是為無狀態的HTTP提供的持久機制。Session工作原理:
當用戶第一次登陸后,客戶端瀏覽器將用戶信息發送給服務器,服務器使用Session為該用戶創建一個SessionId(隨機產生的字串,每個人的都不同)及保存Session內容(用戶基礎信息、權限信息、用戶機構信息、固定變量等,這個數據可以保存在集群、數據庫、文件中,用於跟蹤用戶的狀態等),並在響應內容(Cookie)中將該SessionId一並返回給瀏覽器,瀏覽器再將這些數據保存再本地,當用戶再次發送請求時,瀏覽器會自動把上次請求存儲的Cookie數據自動攜帶給服務器,服務器接收到請求信息后,會通過瀏覽器請求的數據中的SessionId來查找該客戶的狀態就可以了。
Session生成后,只要用戶繼續訪問,服務器就會更新Session的最后訪問時間,並維護該Session。為防止內存溢出,服務器會把長時間內沒有活躍的Session從內存刪除。這個時間就是Session的超時時間。如果超過了超時時間沒訪問過服務器,Session就自動失效了。
這種用戶信息存儲方式相對cookie來說更安全,可是session有一個缺陷:如果web服務器做了負載均衡,那么下一個操作請求到了另一台服務器的時候session會丟失。
三、Token(令牌):用戶身份驗證方式
當客戶端第一次訪問服務端,服務端會根據傳過來的唯一標識userId,運用一些算法,並加上密鑰,生成一個Token,然后通過BASE64編碼一下之后將這個Token返回給客戶端,客戶端將Token保存起來(可以通過數據庫或文件形式保存本地)。下次請求時,客戶端只需要帶上Token,服務器收到請求后,會用相同的算法和密鑰去驗證Token和有效期。
最簡單的Token組成:uid(用戶唯一的身份標識)、time(當前時間的時間戳)、sign(簽名,由Token的前幾位+鹽以哈希算法壓縮成一定長的十六進制字符串,可以防止惡意第三方拼接Token請求服務器)。
使用基於 Token 的身份驗證方法,在服務端不需要存儲用戶的登錄記錄。大概的流程是這樣的:
1.客戶端使用用戶名跟密碼請求登錄;
2.服務端收到請求,去驗證用戶名與密碼;
3.驗證成功后,服務端會簽發一個 Token,再把這個 Token 發送給客戶端;
4.客戶端收到 Token 以后可以把它存儲起來,比如放在 Cookie 里或者數據庫里;
5.客戶端每次向服務端請求資源的時候需要帶着服務端簽發的 Token;
6.服務端收到請求,然后去驗證客戶端請求里面帶着的 Token,如果驗證成功,就向客戶端返回請求的數據,失敗則返回錯誤信息,讓他重新登錄。
總結:
作為身份認證token安全性比session好,因為每個請求都有表明還能防止監聽及重放攻擊,而session就必須靠鏈路層來保障通訊安全。比如:如果你需要實現有狀態的會話,仍然可以增加session來在服務器端保存一些狀態。Session 認證只是簡單的把User 信息存儲到Session 里(有此SID即認為有此User的全部權利),因為SID 的不可預測性,暫且認為是安全的。而Token ,如果指的是OAuth Token 或類似的機制的話,提供的是"認證" 和"授權" ,認證是針對用戶,授權是針對App 。其目的是讓某App有權利訪問某用戶的信息,這里的 Token是唯一的,不可以轉移到其它 App上,也不可以轉到其它用戶上。所以簡單來說,如果你的用戶數據可能需要和第三方共享,或者允許第三方調用 API 接口,就用 Token 。如果永遠只是自己的網站,自己的 App,用什么就無所謂了。
Token就是令牌,比如你授權(登錄)一個程序時,他就是個依據,判斷你是否已經授權該軟件;
Cookie就是寫在客戶端的一個txt文件,里面包括你登錄信息之類的,這樣你下次在登錄某個網站,就會自動調用Cookie自動登錄用戶名;
Session和Cookie差不多,只是Session是寫在服務器端的文件,也需要在客戶端寫入Cookie文件,但是文件里是你的瀏覽器編號.
Session的狀態是存儲在服務器端,客戶端只有session id;而Token的狀態是存儲在客戶端。
Cookie是不允許垮域訪問的,但是token是支持的(前提是傳輸的用戶認證信息通過HTTP頭傳輸)。
互聯網服務離不開用戶認證。一般流程是下面這樣:
1、用戶向服務器發送用戶名和密碼。
2、服務器驗證通過后,在當前對話(session)里面保存相關數據,比如用戶角色、登錄時間等等。
3、服務器向用戶返回一個 session_id,寫入用戶的 Cookie。
4、用戶隨后的每一次請求,都會通過 Cookie,將 session_id 傳回服務器。
5、服務器收到 session_id,找到前期保存的數據,由此得知用戶的身份。
這種模式的擴展性不好:單機是沒有問題,如果是服務器集群或者是跨域的服務導向架構,就要求 session 數據共享,每台服務器都能夠讀取 session。
一種解決方案是: session 數據持久化,寫入數據庫或別的持久層。各種服務收到請求后,都向持久層請求數據。這種方案工程量比較大,持久層萬一掛了,就會單點失敗。
另一種方案是:服務器索性不保存 session 數據了,所有數據都保存在客戶端,每次請求都發回服務器。JWT 就是這種方案的一個代表。
JSON Web Token(縮寫 JWT)是目前最流行的跨域認證解決方案 :
JWT 的原理是,服務器認證以后,生成一個 JSON 對象,發回給用戶,就像下面這樣。
{
"姓名": "張三",
"角色": "管理員",
"到期時間": "2018年7月1日0點0分"
}
以后,用戶與服務端通信的時候,都要發回這個 JSON 對象。服務器完全只靠這個對象認定用戶身份。為了防止用戶篡改數據,服務器在生成這個對象的時候,會加上簽名(詳見后文)。
JWT 的三個部分:Header(頭部)、Payload(負載)、Signature(簽名):
Header 部分是一個 JSON 對象,描述 JWT 的元數據,通常是下面的樣子
{
"alg": "HS256", // alg屬性表示簽名的算法(algorithm),默認是 HMAC SHA256(寫成 HS256)
"typ": "JWT" // typ屬性表示這個令牌(token)的類型(type)
}
Payload 部分也是一個 JSON 對象,用來存放實際需要傳遞的數據。注意,JWT 默認是不加密的,任何人都可以讀到,所以不要把秘密信息放在這個部分。
Signature 部分是對前兩部分的簽名,防止數據篡改。
首先,需要指定一個密鑰(secret)。這個密鑰只有服務器才知道,不能泄露給用戶。然后,使用 Header 里面指定的簽名算法(默認是 HMAC SHA256),按照下面的公式產生簽名。
算出簽名以后,把 Header、Payload、Signature 三個部分拼成一個字符串,每個部分之間用"點"(.)分隔,就可以返回給用戶。
后續繼續深入學習。。。