【干貨建議收藏】Java中session、cookie、token的區(qū)別
一.Cookie
1.什么是cookie?
Cookie 技術(shù)產(chǎn)生源于 HTTP 協(xié)議在互聯(lián)網(wǎng)上的急速發(fā)展。隨著互聯(lián)網(wǎng)時代的策馬奔騰,帶寬等限制不存在了,人們需要更復(fù)雜的互聯(lián)網(wǎng)交互活動,就必須同服務(wù)器保持活動狀態(tài)(簡稱:?;睿?/span>
Cookie 是在 HTTP 協(xié)議下,服務(wù)器或腳本可以維護(hù)客戶工作站上信息的一種方式。Cookie 是由 Web 服務(wù)器保存在用戶瀏覽器(客戶端)上的小文本文件,它可以包含有關(guān)用戶的信息。無論何時用戶鏈接到服務(wù)器,Web 站點都可以訪問 Cookie 信息.
2.cookie的起源
Cookie最早是網(wǎng)景公司的前雇員Lou Montulli在1993年3月的發(fā)明。
3.Cookie時效性
Cookie的默認(rèn)時效為Session,也就是說瀏覽器關(guān)閉,Cookie會和session一起失效,但是Cookie的有效時間是可以設(shè)置的。
Cookie有一個屬性expires,設(shè)置其值為一個時間,那么當(dāng)?shù)竭_(dá)此時間后,此cookie失效。
實現(xiàn)如下:
??
4.Cookie文件的刪除、銷毀
由于 Cookie 在用戶的計算機(jī)中,所以無法直接將其直接移除。所以我們用瀏覽器來刪除 Cookie。首先是創(chuàng)建一個與要刪除的 Cookie 同名的新 Cookie,將該 Cookie 的到期日期設(shè)置為早于當(dāng)前日期的某個日期,當(dāng)瀏覽器檢查 Cookie 的到期日期時,瀏覽器便會丟棄這個現(xiàn)已過期的 Cookie。
5.Cookie使用限制
Cookie是HTTP頭中的一個字段,雖然HTTP本身對這個字段并沒有多少限制,但是Cookie最終還是存儲在瀏覽器里,所以不同的瀏覽器對Cookie的存儲都有一些限制,不同的瀏覽器對 Cookie 的處理不一致,使用時一定要考慮。
客戶端用戶如果設(shè)置禁止 Cookie,則 Cookie 不能建立。 并且在客戶端,一個瀏覽器能創(chuàng)建的 Cookie 數(shù)量根據(jù)瀏覽器的不同,其上限也不同。

6.執(zhí)行流程:
1)、首先,客戶端會發(fā)送一個http請求到服務(wù)器端。
2)、服務(wù)器端接受客戶端請求后,發(fā)送一個http響應(yīng)到客戶端,這個響應(yīng)頭,其中就包含Set-Cookie頭部,瀏覽器保存Cookie。
3)、瀏覽器第二次訪問,將保存的cookie發(fā)給后臺,后臺識別并更新cookie,返回瀏覽器再次保存。
為了方便理解,可以先看下這張流程執(zhí)行圖加深概念

那么,在瀏覽器上面的請求頭和Cookie在那?下圖給大家截取了其中一種。

上面我們都是在談瀏覽器上的Cookie,那么在Android開發(fā)中,我們該如何去管理和使用Cookie?
7.Okhttp框架(本文是基于Okhttp3.0版本以上)
Okhttp是一款相當(dāng)經(jīng)典的網(wǎng)絡(luò)框架,它的API可以通過OkhttpClient中的CookieJar或者攔截器去管理Cookie的。
我們在構(gòu)建單例OkhttpClient的時候,設(shè)置cookiejar或者攔截器,然后具體的操作(保存Cookie,取Cookie),Okhttp框架就會幫我們自動管理Cookie。
如下圖:

這是其中一種通過集合的增查特性,就可以簡單有效的幫我們管理Cookie。但我們還是要通過源代碼去一探究竟。首先,CookieJar是一個接口。

英文注釋翻譯過來就是:
CookieJar這個接口為HTTP cookies提供了強(qiáng)大的支持和相關(guān)策略。
這種策略的實現(xiàn)作用會負(fù)責(zé)選擇接受和拒絕那些cookie。一個合理的策略是拒絕所有的cookie,盡管這樣會干擾需要cookie的基于會話的自身身份驗證方案。
作為Cookie的持久性,該接口的實現(xiàn)也必須要提供Cookie的存儲。一種簡單的實現(xiàn)可以將cookie存儲在內(nèi)存中;復(fù)雜的系統(tǒng)可以使用文件系統(tǒng)用于保存已接受的cookie的數(shù)據(jù)庫。
所以,Okhttp的源碼告知我們可以將cookie存儲在內(nèi)存中;復(fù)雜的系統(tǒng)可以使用文件系統(tǒng)用于保存已接受的cookie的數(shù)據(jù)庫。因此,我們就可以通過Map去簡單的管理和使用。
繼續(xù)分析CookieJar接口里面的方法,依舊上源碼

里面有方法一個是saveFromResponse(HttpUrl url, List cookies)、loadForRequest(HttpUrl url)
saveFromResponse方法注釋:根據(jù)這個jar的方法,可以將cookie從一個HTTP響應(yīng)保存到這里。如果有響應(yīng),此方法可能會引起第二次HTTP響應(yīng),包括一個追蹤。對于這個隱蔽的HTTP特性,這里的cookie只包含其追蹤的cookie。簡單點理解就是如果我們使用了這個方法,就會進(jìn)行追蹤(也就是說客戶端請求成功以后,在響應(yīng)頭里面存cookie)
loadForRequest方法注釋:將cookie從這個方法加載到一個HTTP請求到指定的url。但是這個方法從網(wǎng)絡(luò)上返回的結(jié)果可能是一個空集合。簡單的實現(xiàn)將返回的尚未過期的并且已接受的cookie去進(jìn)行匹配。(也就是加載url的時候在請求頭帶上cookie)。

這樣,我們通過以上代碼就可以完成了Cookie的非持久化。
那么這個非持久化又是什么呢?
前面我們說了,Cookie是具有時效性的,所以,Cookie的管理又分為持久化Cookie和非持久化Cookie。
非持久化Cookie存儲在內(nèi)存中,也就意味著,其生命周期基本和App保持一致,App關(guān)閉后,Cookie丟失,一般我們也不使用這種方式。
持久化Cookie則是存儲在本地磁盤中,App關(guān)閉后不丟失。
那么,如果我們要使用Cookie的持久化策略,大體上可以參照上面的非持久化策略,只是需要將存儲方式改一下即可:
1).通過響應(yīng)攔截器從response取出cookie并保存到本地,通過請求攔截器從本地取出cookie并添加到請求中
2).自定義CookieJar,在saveFromResponse方法中保存cookie到本地,在loadForRequest方法從本地取出cookie。
那么在這里主要介紹如何通過Okhttp的攔截器去進(jìn)行持久化cookie操作。

1).保存cookie攔截器

2).保存cookie攔截器
這個SaveCookiesInterceptor攔截器的實現(xiàn),是首先從response獲取set-cookie字段的值,然后通過SharedPreferences保存在本地。

將Cookie添加到請求頭:
AddCookiesInterceptor請求攔截器,這個攔截的作用就是判斷如果該請求存在cookie,則為其添加到Header的Cookie中。
寫好這兩個攔截器之后,我們只需要將實例對象放進(jìn)OkhttpClient里面即可快速的完成Cookie持久化操作。(這兩個攔截器在同步Cookie的時候也很好用)

Okhttp使用cookie攔截器
二.Session
Session是一個會話,會話就是Session。Session是對于服務(wù)端來說的,Session是服務(wù)器和客戶端建立連接時添加的一個客戶端連接標(biāo)志,最終在服務(wù)器軟件(Apache、Tomcat、JBoss)轉(zhuǎn)化為一個臨時的Cookie發(fā)送給客戶端,當(dāng)客戶端第一次請求服務(wù)器時,會檢查是否攜帶了這個Session(臨時Cookie),如果沒有則會添加Session,如果有就拿出這個Session來做相關(guān)操作。
那么為什么會出現(xiàn)session會話,它出現(xiàn)的機(jī)理是什么?
我們都知道,用瀏覽器打開一個網(wǎng)頁,用到的是HTTP協(xié)議,了解計算機(jī)的應(yīng)該都知道這個協(xié)議,它是無狀態(tài)的,什么是無狀態(tài)呢?就是說這一次請求和上一次請求是沒有任何關(guān)系的,互不認(rèn)識的,沒有關(guān)聯(lián)的。但是這種無狀態(tài)的的好處是快速。所以就會帶來一個問題就是,請求的頁面沒有關(guān)聯(lián)
于是,這個時候,一種新的存儲會話機(jī)制:session 誕生了。
Session 就是在一次會話中解決2次HTTP的請求的關(guān)聯(lián),讓它們產(chǎn)生聯(lián)系,讓2兩個頁面都能讀取到找個這個全局的session信息。session信息存在于服務(wù)器端,所以也就很好的解決了安全問題。
每個Session 有一個唯一的Session id。 Session的超時也是由服務(wù)器來控制。我們一般都會把Session和Cookie放在一起來說,它們具體的區(qū)別和聯(lián)系這里我就不多說了,可以看上面。Cookie分為內(nèi)存中Cookie(也可以說是進(jìn)程中Cookie)和硬盤中Cookie。大部分的Session機(jī)制都使用進(jìn)程中Cookie來保存Session id的,關(guān)閉瀏覽器后這個進(jìn)程也就自動消失了,進(jìn)程中的Cookie自然就消失了,那么Session id也跟著消失了,再次連接到服務(wù)器時也就無法找到原來的Session了。
也有使用硬盤中Cookie,比如說CSDN的“記住我一周”,或者我們的購物車信息可以在切換不同瀏覽器時依然可用。這就要用到我們上文提到的另一種Cookie了——硬盤中Cookie,這時Session id將長期保存在硬盤上的Cookie中,直到失效為止。
三.Token
token是用戶身份的驗證方式,我們通常叫它:令牌。
最簡單的token組成:
uid(用戶唯一的身份標(biāo)識)
time(當(dāng)前時間的時間戳)
sign(簽名,由token的前幾位+鹽以哈希算法壓縮成一定長的十六進(jìn)制字符串,可以防止惡意第三方拼接token請求服務(wù)器)。
還可以把不變的參數(shù)也放進(jìn)token,避免多次查庫。
應(yīng)用場景:
1):當(dāng)用戶首次登錄成功(注冊也是一種可以適用的場景)之后, 服務(wù)器端就會生成一個 token 值,這個值,會在服務(wù)器保存token值(保存在數(shù)據(jù)庫中),再將這個token值返回給客戶端.
2):客戶端拿到 token 值之后,進(jìn)行本地保存。(SP存儲是大家能夠比較支持和易于理解操作的存儲)
3):當(dāng)客戶端再次發(fā)送網(wǎng)絡(luò)請求(一般不是登錄請求)的時候,就會將這個 token 值附帶到參數(shù)中發(fā)送給服務(wù)器.
4):服務(wù)器接收到客戶端的請求之后,會取出token值與保存在本地(數(shù)據(jù)庫)中的token值做對比
對比一:如果兩個 token 值相同, 說明用戶登錄成功過!當(dāng)前用戶處于登錄狀態(tài)!
對比二:如果沒有這個 token 值, 則說明沒有登錄成功.
對比三:如果 token 值不同: 說明原來的登錄信息已經(jīng)失效,讓用戶重新登錄.
四.Cookie和Session的區(qū)別:
cookie數(shù)據(jù)存放在客戶的瀏覽器上,session數(shù)據(jù)放在服務(wù)器上。
cookie不是很安全,別人可以分析存放在本地的cookie并進(jìn)行cookie欺騙,考慮到安全應(yīng)當(dāng)使用session。
session會在一定時間內(nèi)保存在服務(wù)器上。當(dāng)訪問增多,會比較占用你服務(wù)器的性能,考慮到減輕服務(wù)器性能方面,應(yīng)當(dāng)使用cookie。
單個cookie保存的數(shù)據(jù)不能超過4K,很多瀏覽器都限制一個站點最多保存20個cookie。
所以個人建議:
將登陸信息等重要信息存放為session
其他信息如果需要保留,可以放在cookie中
五.Token 和 Session 的區(qū)別:
session和 token并不矛盾,作為身份認(rèn)證token安全性比session好,因為每個請求都有簽名還能防止監(jiān)聽以及重放攻擊,而session就必須靠鏈路層來保障通訊安全了。如上所說,如果你需要實現(xiàn)有狀態(tài)的會話,仍然可以增加session來在服務(wù)器端保存一些狀態(tài)。
App通常用restful api跟server打交道。Rest是stateless的,也就是App不需要像browser那樣用cookie來保存session,因此用session token來標(biāo)示自己就夠了,session/state由api server的邏輯處理。如果你的后端不是stateless的rest api,那么你可能需要在App里保存session.可以在App里嵌入webkit,用一個隱藏的browser來管理cookie session.
Session是一種HTTP存儲機(jī)制,目的是為無狀態(tài)的HTTP提供的持久機(jī)制。所謂Session認(rèn)證只是簡單的把User信息存儲到Session里,因為SID的不可預(yù)測性,暫且認(rèn)為是安全的。這是一種認(rèn)證手段。而Token,如果指的是OAuth Token或類似的機(jī)制的話,提供的是 認(rèn)證 和 授權(quán) ,認(rèn)證是針對用戶,授權(quán)是針對App。
其目的是讓 某App有權(quán)利訪問 某用戶 的信息。這里的Token是唯一的。不可以轉(zhuǎn)移到其它App上,也不可以轉(zhuǎn)到其它 用戶 上。轉(zhuǎn)過來說Session。Session只提供一種簡單的認(rèn)證,即有此SID,即認(rèn)為有此User的全部權(quán)利。是需要嚴(yán)格保密的,這個數(shù)據(jù)應(yīng)該只保存在站方,不應(yīng)該共享給其它網(wǎng)站或者第三方App。所以簡單來說,如果你的用戶數(shù)據(jù)可能需要和第三方共享,或者允許第三方調(diào)用API接口,用Token。如果永遠(yuǎn)只是自己的網(wǎng)站,自己的App,用什么就無所謂了。
token就是令牌,比如你授權(quán)(登錄)一個程序時,他就是個依據(jù),判斷你是否已經(jīng)授權(quán)該軟件;cookie就是寫在客戶端的一個txt文件,里面包括你登錄信息之類的,這樣你下次在登錄某個網(wǎng)站,就會自動調(diào)用cookie自動登錄用戶名;session和cookie差不多,只是session是寫在服務(wù)器端的文件,也需要在客戶端寫入cookie文件,但是文件里是你的瀏覽器編號.Session的狀態(tài)是存儲在服務(wù)器端,客戶端只有session id;而Token的狀態(tài)是存儲在客戶端。