? ? ? 之前也是看了很多session、cookie & token相關(guān)的介紹文章,還不是很清楚的理解,所以今天把這塊的知識(shí)點(diǎn)再整理下,也是為了讓自己更加理解下,首先默默地在心里問幾個(gè)問題,為什么要有session、cookie 和 token呢?都有什么原理?又有什么作用?
帶著這些問題,我們先依次理以下幾個(gè)概念:
Http是一種無狀態(tài)的協(xié)議
無狀態(tài)是指上一次的請(qǐng)求和這一次沒有關(guān)系,沒有關(guān)聯(lián),不需要記錄瀏覽了什么內(nèi)容,每次發(fā)送的請(qǐng)求都是全新的,好處很明顯就是快!當(dāng)然也有不好的一面,就是當(dāng)把同個(gè)域名下有關(guān)聯(lián)的網(wǎng)頁(yè)要關(guān)聯(lián)起來就得依靠一些工具,譬如網(wǎng)購(gòu)的時(shí)候商品瀏覽、購(gòu)買、配送,如何確定是誰在看什么商品,買什么商品,給寄送到哪去怎么關(guān)聯(lián)起來呢。
由于Http是無狀態(tài)的,為了使同一個(gè)域名下所有網(wǎng)頁(yè)共享某些數(shù)據(jù),就出現(xiàn)cookie和session。
Cookie
cookie是瀏覽器里可以永久存儲(chǔ)的一種數(shù)據(jù),是瀏覽器實(shí)現(xiàn)存儲(chǔ)數(shù)據(jù)的一種實(shí)現(xiàn)方式。
cookie一般是由服務(wù)器生成的,發(fā)送給瀏覽器端,瀏覽器把cookie以KV的形式存儲(chǔ)到某個(gè)目錄下文本文件,下一次請(qǐng)求同一網(wǎng)站時(shí)會(huì)把該cookie發(fā)送給服務(wù)器。
如何設(shè)置cookie呢?分成客戶端和服務(wù)端設(shè)置,先介紹下客戶端設(shè)置:
客戶端設(shè)置cookie的選項(xiàng)有expires, domain, path, secure(secure只在https協(xié)議的網(wǎng)頁(yè)中, 客戶端設(shè)置secure類型cookie才能生效)。設(shè)置好cookie會(huì)自動(dòng)添加到request header中,然后服務(wù)端接收到cookie。
服務(wù)端設(shè)置cookie,不管是請(qǐng)求個(gè)什么資源文件還是ajax請(qǐng)求,服務(wù)端都會(huì)返回response,在response的header中有一項(xiàng)叫set-cookie,是服務(wù)端專門來設(shè)置cookie的。

【額外補(bǔ)充點(diǎn)】HTML5提供了兩種本地存儲(chǔ)的方式 sessionStorage 和 localStorage:

session
session就是會(huì)話,也是由服務(wù)端生產(chǎn)的,因?yàn)榉?wù)器端要區(qū)分當(dāng)前的請(qǐng)求是誰發(fā)的,為了做這種區(qū)分,服務(wù)端就要給客戶端做不同的身份標(biāo)識(shí),然后客戶端每次請(qǐng)求的時(shí)候都會(huì)帶上這個(gè)身份標(biāo)識(shí)。那服務(wù)器端就能區(qū)分請(qǐng)求來自于誰了。
那如何保存session呢?實(shí)現(xiàn)方式有很多種,對(duì)于瀏覽端,可以采用cookie的方式。
一般也是用cookie+session,不會(huì)單獨(dú)使用,雖然單獨(dú)保存也會(huì)保持會(huì)話狀態(tài)。

存在問題,擴(kuò)展性不好,單機(jī)沒有問題,如果是服務(wù)器集群,或者是跨域的服務(wù)導(dǎo)向架構(gòu),那就要求session數(shù)據(jù)共享,每臺(tái)服務(wù)器都要讀取session。舉例說下,同一個(gè)公司多個(gè)網(wǎng)站要實(shí)現(xiàn)單點(diǎn)登錄(登錄一個(gè)網(wǎng)站,然后訪問另外一個(gè)網(wǎng)站時(shí)自動(dòng)登錄)。
策略1:Nginx ip_hash 策略,服務(wù)端使用 Nginx 代理,每個(gè)請(qǐng)求按訪問 IP 的 hash 分配,這樣來自同一 IP 固定訪問一個(gè)后臺(tái)服務(wù)器,避免了在服務(wù)器 A 創(chuàng)建 Session,第二次分發(fā)到服務(wù)器 B 的現(xiàn)象。
策略2:Session復(fù)制,任何一個(gè)服務(wù)器上的 Session 發(fā)生改變(增刪改),該節(jié)點(diǎn)會(huì)把這個(gè) Session 的所有內(nèi)容序列化,然后廣播給所有其它節(jié)點(diǎn)。
策略3:共享Session:將Session Id 集中存儲(chǔ)到一個(gè)地方,所有的機(jī)器都來訪問這個(gè)地方的數(shù)據(jù)。這種方案的優(yōu)點(diǎn)是架構(gòu)清晰,缺點(diǎn)是工程量比較大。另外,持久層萬一掛了,就會(huì)單點(diǎn)失敗。
另一種是服務(wù)器索性不存session數(shù)據(jù)了,所有數(shù)據(jù)就保存在客戶端,每次請(qǐng)求都發(fā)回服務(wù)器。這種方案就是接下來要介紹的基于Token的驗(yàn)證。
Token
token也稱作令牌,由uid+time時(shí)間戳+sign【+固定參數(shù)】組成:
uid:用戶身份唯一標(biāo)識(shí)
time:當(dāng)前時(shí)間的時(shí)間戳
sign:簽名,使用hash/encrypt壓縮成定長(zhǎng)的十六進(jìn)制字符串,以防止第三方惡意拼接
【固定參數(shù)(可選)】:把一些常用固定參數(shù)加到token中,避免重復(fù)查庫(kù)
token的認(rèn)證也是類似于臨時(shí)的證書簽名,并且是一種服務(wù)端無狀態(tài)的驗(yàn)證方式,適用于rest api 的場(chǎng)景,所謂無狀態(tài)是指服務(wù)端不會(huì)保存身份認(rèn)證的相關(guān)數(shù)據(jù);
存儲(chǔ):token一般儲(chǔ)存在localstorage、cookie或sessionstorage中。在服務(wù)器存儲(chǔ)在數(shù)據(jù)庫(kù)。認(rèn)證流程和cookie基本一致,如下圖:

還有現(xiàn)成實(shí)現(xiàn)的標(biāo)準(zhǔn)JWT(JSON Web Token),JWT最開始的初衷是為了實(shí)現(xiàn)授權(quán)和身份認(rèn)證作用的,可以實(shí)現(xiàn)無狀態(tài),分布式的Web應(yīng)用授權(quán)。大致實(shí)現(xiàn)的流程如下。JSON Web Tokens由dot(.)分隔的三個(gè)部分組成,它們是:
Header(頭部)
Payload(負(fù)載)
Signature(簽名)
通常如下展示是<p>xxxxx.yyyyy.zzzz</p>。

1、客戶端需要攜帶用戶名/密碼等可證明身份的的內(nèi)容去授權(quán)服務(wù)器獲取JWT信息;
2、每次服務(wù)都攜帶該Token內(nèi)容與Web服務(wù)器進(jìn)行交互,由業(yè)務(wù)服務(wù)器來驗(yàn)證Token是否是授權(quán)發(fā)放的有效Token,來驗(yàn)證當(dāng)前業(yè)務(wù)是否請(qǐng)求合法。
這里需要注意:不是每次請(qǐng)求都要申請(qǐng)一次Token,這是需要注意,如果不是對(duì)于安全性要求的情況,不建議每次都申請(qǐng),因?yàn)闀?huì)增加業(yè)務(wù)耗時(shí);比如只在登陸時(shí)申請(qǐng),然后使用JWT的過期時(shí)間或其他手段來保證JWT的有效性;
區(qū)別
Cookie和Session的區(qū)別
1、存儲(chǔ)位置不同: cookie數(shù)據(jù)存放在客戶的瀏覽器上,session數(shù)據(jù)放在服務(wù)器上
2、隱私策略不同:cookie不是很安全, 別人可以分析存放在本地的cookie并進(jìn)行cookie欺騙,考慮到安全應(yīng)當(dāng)使用session
3、session會(huì)在一定時(shí)間內(nèi)保存在服務(wù)器上。當(dāng)訪問增多,就會(huì)比較占用你服務(wù)器的性能,考慮到減輕服務(wù)器性能方面,應(yīng)當(dāng)使用cookie
4、存儲(chǔ)大小不同: 單個(gè)cookie保存的數(shù)據(jù)不能超過4k, 很多瀏覽器都限制一個(gè)站點(diǎn)最多保存20個(gè)cookie
Token和Session的區(qū)別
Session是一種HTTP儲(chǔ)存機(jī)制, 為無狀態(tài)的HTTP提供持久機(jī)制;
Token就是令牌, 比如你授權(quán)(登錄)一個(gè)程序時(shí),它就是個(gè)依據(jù),判斷你是否已經(jīng)授權(quán)該軟件;
Session和Token并不矛盾,作為身份認(rèn)證Token安全性比Session好,因?yàn)槊恳粋€(gè)請(qǐng)求都有簽名還能防止監(jiān)聽以及重放攻擊,而Session就必須依賴鏈路層來保障通訊安全了。如上所說,如果你需要實(shí)現(xiàn)有狀態(tài)的回話,仍然可以增加Session來在服務(wù)端保存一些狀態(tài)。
總結(jié)
cookie,session,Token沒有絕對(duì)好與壞之分,只要還是要結(jié)合實(shí)際的業(yè)務(wù)場(chǎng)景和需求來決定采用哪種方式來管理回話,當(dāng)然也可以三種都用。