一.Cookie
1.什么是cookie?
Cookie 技術(shù)產(chǎn)生源于 HTTP 協(xié)議在互聯(lián)網(wǎng)上的急速發(fā)展猜惋。隨著互聯(lián)網(wǎng)時(shí)代的策馬奔騰丸氛,帶寬等限制不存在了,人們需要更復(fù)雜的互聯(lián)網(wǎng)交互活動(dòng)著摔,就必須同服務(wù)器保持活動(dòng)狀態(tài)(簡(jiǎn)稱:被捍埽活)。
Cookie 是在 HTTP 協(xié)議下谍咆,服務(wù)器或腳本可以維護(hù)客戶工作站上信息的一種方式禾锤。Cookie 是由 Web 服務(wù)器保存在用戶瀏覽器(客戶端)上的小文本文件,它可以包含有關(guān)用戶的信息摹察。無(wú)論何時(shí)用戶鏈接到服務(wù)器恩掷,Web 站點(diǎn)都可以訪問(wèn) Cookie 信息.
2.cookie的起源
Cookie最早是網(wǎng)景公司的前雇員Lou Montulli在1993年3月的發(fā)明。
3.Cookie時(shí)效性
Cookie的默認(rèn)時(shí)效為Session供嚎,也就是說(shuō)瀏覽器關(guān)閉黄娘,Cookie會(huì)和session一起失效,但是Cookie的有效時(shí)間是可以設(shè)置的查坪。
Cookie有一個(gè)屬性expires寸宏,設(shè)置其值為一個(gè)時(shí)間,那么當(dāng)?shù)竭_(dá)此時(shí)間后偿曙,此cookie失效氮凝。
實(shí)現(xiàn)如下:
//創(chuàng)建cookie實(shí)例。
HttpCookie cookie = new HttpCookie("id","666");
//設(shè)置cookie的過(guò)期時(shí)間望忆,一小時(shí)后過(guò)期罩阵,自動(dòng)清除文件
cookie.Expires = DateTime.Now.AddMonths(60);
//將創(chuàng)建的cookie文件輸入到瀏覽器端
Response.Cookies.Add(cookie);
//讀取cookie文件中存儲(chǔ)的值
Response.Write(Request.Cookies["id"].Value);
4.Cookie文件的刪除竿秆、銷毀
由于 Cookie 在用戶的計(jì)算機(jī)中,所以無(wú)法直接將其直接移除稿壁。所以我們用瀏覽器來(lái)刪除 Cookie幽钢。首先是創(chuàng)建一個(gè)與要?jiǎng)h除的 Cookie 同名的新 Cookie,將該 Cookie 的到期日期設(shè)置為早于當(dāng)前日期的某個(gè)日期傅是,當(dāng)瀏覽器檢查 Cookie 的到期日期時(shí)匪燕,瀏覽器便會(huì)丟棄這個(gè)現(xiàn)已過(guò)期的 Cookie。
//cookie的銷毀喧笔,給他設(shè)置一個(gè)時(shí)間帽驯,他就被銷毀了
cookie.Expires = DateTime.Now.AddMonths(-60);
5.Cookie使用限制
Cookie是HTTP頭中的一個(gè)字段,雖然HTTP本身對(duì)這個(gè)字段并沒(méi)有多少限制书闸,但是Cookie最終還是存儲(chǔ)在瀏覽器里尼变,所以不同的瀏覽器對(duì)Cookie的存儲(chǔ)都有一些限制,不同的瀏覽器對(duì) Cookie 的處理不一致浆劲,使用時(shí)一定要考慮嫌术。
客戶端用戶如果設(shè)置禁止 Cookie,則 Cookie 不能建立牌借。 并且在客戶端度气,一個(gè)瀏覽器能創(chuàng)建的 Cookie 數(shù)量根據(jù)瀏覽器的不同,其上限也不同走哺。
6.執(zhí)行流程:
1)蚯嫌、首先,客戶端會(huì)發(fā)送一個(gè)http請(qǐng)求到服務(wù)器端丙躏。
2)择示、服務(wù)器端接受客戶端請(qǐng)求后,發(fā)送一個(gè)http響應(yīng)到客戶端晒旅,這個(gè)響應(yīng)頭栅盲,其中就包含Set-Cookie頭部,瀏覽器保存Cookie废恋。
3)谈秫、瀏覽器第二次訪問(wèn),將保存的cookie發(fā)給后臺(tái)鱼鼓,后臺(tái)識(shí)別并更新cookie拟烫,返回瀏覽器再次保存。
為了方便理解迄本,可以先看下這張流程執(zhí)行圖加深概念
那么硕淑,在瀏覽器上面的請(qǐng)求頭和Cookie在那?下圖給大家截取了其中一種。
上面我們都是在談瀏覽器上的Cookie置媳,那么在Android開(kāi)發(fā)中于樟,我們?cè)撊绾稳ス芾砗褪褂肅ookie?
7.Okhttp框架(本文是基于Okhttp3.0版本以上)
Okhttp是一款相當(dāng)經(jīng)典的網(wǎng)絡(luò)框架拇囊,它的API可以通過(guò)OkhttpClient中的CookieJar或者攔截器去管理Cookie的迂曲。
我們?cè)跇?gòu)建單例OkhttpClient的時(shí)候,設(shè)置cookiejar或者攔截器寥袭,然后具體的操作(保存Cookie路捧,取Cookie),Okhttp框架就會(huì)幫我們自動(dòng)管理Cookie纠永。
如下圖:
這是其中一種通過(guò)集合的增查特性鬓长,就可以簡(jiǎn)單有效的幫我們管理Cookie谒拴。但我們還是要通過(guò)源代碼去一探究竟尝江。首先,CookieJar是一個(gè)接口英上。
英文注釋翻譯過(guò)來(lái)就是:
CookieJar這個(gè)接口為HTTP cookies提供了強(qiáng)大的支持和相關(guān)策略炭序。
這種策略的實(shí)現(xiàn)作用會(huì)負(fù)責(zé)選擇接受和拒絕那些cookie。一個(gè)合理的策略是拒絕所有的cookie苍日,盡管這樣會(huì)干擾需要cookie的基于會(huì)話的自身身份驗(yàn)證方案惭聂。
作為Cookie的持久性,該接口的實(shí)現(xiàn)也必須要提供Cookie的存儲(chǔ)相恃。一種簡(jiǎn)單的實(shí)現(xiàn)可以將cookie存儲(chǔ)在內(nèi)存中;復(fù)雜的系統(tǒng)可以使用文件系統(tǒng)用于保存已接受的cookie的數(shù)據(jù)庫(kù)辜纲。這里的鏈接https://tools.ietf.org/html/rfc6265 指定cookie存儲(chǔ)模型更新和過(guò)期的cookie的策略。
所以拦耐,Okhttp的源碼告知我們可以將cookie存儲(chǔ)在內(nèi)存中;復(fù)雜的系統(tǒng)可以使用文件系統(tǒng)用于保存已接受的cookie的數(shù)據(jù)庫(kù)耕腾。因此,我們就可以通過(guò)Map去簡(jiǎn)單的管理和使用杀糯。
繼續(xù)分析CookieJar接口里面的方法扫俺,依舊上源碼
里面有方法一個(gè)是saveFromResponse(HttpUrl url, List cookies)、loadForRequest(HttpUrl url)
saveFromResponse方法注釋:根據(jù)這個(gè)jar的方法固翰,可以將cookie從一個(gè)HTTP響應(yīng)保存到這里狼纬。如果有響應(yīng),此方法可能會(huì)引起第二次HTTP響應(yīng)骂际,包括一個(gè)追蹤疗琉。對(duì)于這個(gè)隱蔽的HTTP特性,這里的cookie只包含其追蹤的cookie歉铝。簡(jiǎn)單點(diǎn)理解就是如果我們使用了這個(gè)方法盈简,就會(huì)進(jìn)行追蹤(也就是說(shuō)客戶端請(qǐng)求成功以后,在響應(yīng)頭里面存cookie)
loadForRequest方法注釋:將cookie從這個(gè)方法加載到一個(gè)HTTP請(qǐng)求到指定的url。但是這個(gè)方法從網(wǎng)絡(luò)上返回的結(jié)果可能是一個(gè)空集合送火。簡(jiǎn)單的實(shí)現(xiàn)將返回的尚未過(guò)期的并且已接受的cookie去進(jìn)行匹配拳话。(也就是加載url的時(shí)候在請(qǐng)求頭帶上cookie)。
這樣种吸,我們通過(guò)以上代碼就可以完成了Cookie的非持久化弃衍。
那么這個(gè)非持久化又是什么呢?
前面我們說(shuō)了坚俗,Cookie是具有時(shí)效性的镜盯,所以,Cookie的管理又分為持久化Cookie和非持久化Cookie猖败。
非持久化Cookie存儲(chǔ)在內(nèi)存中速缆,也就意味著,其生命周期基本和app保持一致,app關(guān)閉后恩闻,Cookie丟失艺糜,一般我們也不使用這種方式髓涯。
持久化Cookie則是存儲(chǔ)在本地磁盤中锯蛀,app關(guān)閉后不丟失掉丽。
那么封孙,如果我們要使用Cookie的持久化策略娃属,大體上可以參照上面的非持久化策略努酸,只是需要將存儲(chǔ)方式改一下即可:
1).通過(guò)響應(yīng)攔截器從response取出cookie并保存到本地灾挨,通過(guò)請(qǐng)求攔截器從本地取出cookie并添加到請(qǐng)求中
2).自定義CookieJar榕吼,在saveFromResponse方法中保存cookie到本地理茎,在loadForRequest方法從本地取出cookie黑界。
那么在這里主要介紹如何通過(guò)Okhttp的攔截器去進(jìn)行持久化cookie操作。
1).保存cookie攔截器
2).保存cookie攔截器
這個(gè)SaveCookiesInterceptor攔截器的實(shí)現(xiàn)皂林,是首先從response獲取set-cookie字段的值朗鸠,然后通過(guò)SharedPreferences保存在本地。
將Cookie添加到請(qǐng)求頭:
AddCookiesInterceptor請(qǐng)求攔截器式撼,這個(gè)攔截的作用就是判斷如果該請(qǐng)求存在cookie童社,則為其添加到Header的Cookie中。
寫好這兩個(gè)攔截器之后著隆,我們只需要將實(shí)例對(duì)象放進(jìn)OkhttpClient里面即可快速的完成Cookie持久化操作扰楼。(這兩個(gè)攔截器在同步Cookie的時(shí)候也很好用)
Okhttp使用cookie攔截器
拓展:如何通過(guò)客戶端的cookie與H5上面的cookie進(jìn)行同步,下面這篇文章很好:
二.Session
Session是一個(gè)會(huì)話美浦,會(huì)話就是Session弦赖。Session是對(duì)于服務(wù)端來(lái)說(shuō)的,Session是服務(wù)器和客戶端建立連接時(shí)添加的一個(gè)客戶端連接標(biāo)志浦辨,最終在服務(wù)器軟件(Apache蹬竖、Tomcat、JBoss)轉(zhuǎn)化為一個(gè)臨時(shí)的Cookie發(fā)送給客戶端,當(dāng)客戶端第一次請(qǐng)求服務(wù)器時(shí)币厕,會(huì)檢查是否攜帶了這個(gè)Session(臨時(shí)Cookie)列另,如果沒(méi)有則會(huì)添加Session,如果有就拿出這個(gè)Session來(lái)做相關(guān)操作旦装。
那么為什么會(huì)出現(xiàn)session會(huì)話页衙,它出現(xiàn)的機(jī)理是什么?
我們都知道阴绢,用瀏覽器打開(kāi)一個(gè)網(wǎng)頁(yè)店乐,用到的是HTTP協(xié)議,了解計(jì)算機(jī)的應(yīng)該都知道這個(gè)協(xié)議呻袭,它是無(wú)狀態(tài)的眨八,什么是無(wú)狀態(tài)呢?就是說(shuō)這一次請(qǐng)求和上一次請(qǐng)求是沒(méi)有任何關(guān)系的左电,互不認(rèn)識(shí)的廉侧,沒(méi)有關(guān)聯(lián)的。但是這種無(wú)狀態(tài)的的好處是快速券腔。所以就會(huì)帶來(lái)一個(gè)問(wèn)題就是伏穆,我希望幾個(gè)請(qǐng)求的頁(yè)面要有關(guān)聯(lián),比如:我在www.a.com/login里面登陸了纷纫,我在www.a.com/index 也希望是登陸狀態(tài),但是陪腌,這是2個(gè)不同的頁(yè)面辱魁,也就是2個(gè)不同的HTTP請(qǐng)求,這2個(gè)HTTP請(qǐng)求是無(wú)狀態(tài)的诗鸭,也就是無(wú)關(guān)聯(lián)的染簇,所以無(wú)法單純的在index中讀取到它在login中已經(jīng)登陸了!
那怎么辦呢强岸?方法一是這2個(gè)頁(yè)面我都去登陸一遍吧锻弓,方法二是用笨方法這2個(gè)頁(yè)面都去查詢數(shù)據(jù)庫(kù),如果有登陸狀態(tài)蝌箍,就判斷是登陸的了青灼。這種查詢數(shù)據(jù)庫(kù)的方案雖然可行,但是每次都要去查詢數(shù)據(jù)庫(kù)不是個(gè)事妓盲,會(huì)造成數(shù)據(jù)庫(kù)的壓力杂拨。 所以正是這種不方便之處,一個(gè)新的客戶端存儲(chǔ)數(shù)據(jù)方式出現(xiàn)了:cookie悯衬。
cookie是把少量的信息存儲(chǔ)在用戶自己的電腦上弹沽,它在一個(gè)域名下是一個(gè)全局的,只要設(shè)置它的存儲(chǔ)路徑在域名www.a.com下 ,那么當(dāng)用戶用瀏覽器訪問(wèn)時(shí)策橘,就可以從這個(gè)域名的任意頁(yè)面讀取cookie中的信息炸渡。所以就很好的解決了我在www.a.com/login頁(yè)面登陸了,我也可以在www.a.com/index獲取到這個(gè)登陸信息了丽已。同時(shí)又不用反復(fù)去查詢數(shù)據(jù)庫(kù)偶摔。 雖然這種方案很不錯(cuò),也很快速方便促脉,但是由于cookie 是存在用戶端辰斋,而且它本身存儲(chǔ)的信息容量也有限,最關(guān)鍵是用戶可以是可見(jiàn)的瘸味,并可以隨意的修改宫仗,很不安全。那如何又要安全旁仿,又可以方便的全局讀取信息呢藕夫?于是,這個(gè)時(shí)候枯冈,一種新的存儲(chǔ)會(huì)話機(jī)制:session 誕生了毅贮。
Session 就是在一次會(huì)話中解決2次HTTP的請(qǐng)求的關(guān)聯(lián),讓它們產(chǎn)生聯(lián)系尘奏,讓2兩個(gè)頁(yè)面都能讀取到找個(gè)這個(gè)全局的session信息滩褥。session信息存在于服務(wù)器端,所以也就很好的解決了安全問(wèn)題炫加。
每個(gè)Session 有一個(gè)唯一的Session id瑰煎。 Session的超時(shí)也是由服務(wù)器來(lái)控制。我們一般都會(huì)把Session和Cookie放在一起來(lái)說(shuō)俗孝,它們具體的區(qū)別和聯(lián)系這里我就不多說(shuō)了酒甸,可以看上面。Cookie分為內(nèi)存中Cookie(也可以說(shuō)是進(jìn)程中Cookie)和硬盤中Cookie赋铝。大部分的Session機(jī)制都使用進(jìn)程中Cookie來(lái)保存Session id的插勤,關(guān)閉瀏覽器后這個(gè)進(jìn)程也就自動(dòng)消失了,進(jìn)程中的Cookie自然就消失了革骨,那么Session id也跟著消失了农尖,再次連接到服務(wù)器時(shí)也就無(wú)法找到原來(lái)的Session了。
也有使用硬盤中Cookie苛蒲,比如說(shuō)CSDN的“記住我一周”卤橄,或者我們的購(gòu)物車信息可以在切換不同瀏覽器時(shí)依然可用。這就要用到我們上文提到的另一種Cookie了——硬盤中Cookie臂外,這時(shí)Session id將長(zhǎng)期保存在硬盤上的Cookie中窟扑,直到失效為止喇颁。
三.Token
token是用戶身份的驗(yàn)證方式,我們通常叫它:令牌嚎货。
最簡(jiǎn)單的token組成:
uid(用戶唯一的身份標(biāo)識(shí))
time(當(dāng)前時(shí)間的時(shí)間戳)
sign(簽名橘霎,由token的前幾位+鹽以哈希算法壓縮成一定長(zhǎng)的十六進(jìn)制字符串,可以防止惡意第三方拼接token請(qǐng)求服務(wù)器)殖属。
還可以把不變的參數(shù)也放進(jìn)token姐叁,避免多次查庫(kù)。
應(yīng)用場(chǎng)景:
1):當(dāng)用戶首次登錄成功(注冊(cè)也是一種可以適用的場(chǎng)景)之后, 服務(wù)器端就會(huì)生成一個(gè) token 值洗显,這個(gè)值外潜,會(huì)在服務(wù)器保存token值(保存在數(shù)據(jù)庫(kù)中),再將這個(gè)token值返回給客戶端.
2):客戶端拿到 token 值之后,進(jìn)行本地保存挠唆。(SP存儲(chǔ)是大家能夠比較支持和易于理解操作的存儲(chǔ))
3):當(dāng)客戶端再次發(fā)送網(wǎng)絡(luò)請(qǐng)求(一般不是登錄請(qǐng)求)的時(shí)候,就會(huì)將這個(gè) token 值附帶到參數(shù)中發(fā)送給服務(wù)器.
4):服務(wù)器接收到客戶端的請(qǐng)求之后,會(huì)取出token值與保存在本地(數(shù)據(jù)庫(kù))中的token值做對(duì)比
對(duì)比一:如果兩個(gè) token 值相同处窥, 說(shuō)明用戶登錄成功過(guò)!當(dāng)前用戶處于登錄狀態(tài)!
對(duì)比二:如果沒(méi)有這個(gè) token 值, 則說(shuō)明沒(méi)有登錄成功.
對(duì)比三:如果 token 值不同: 說(shuō)明原來(lái)的登錄信息已經(jīng)失效,讓用戶重新登錄.
四.Cookie和Session的區(qū)別:
1、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)訪問(wèn)增多摊阀,會(huì)比較占用你服務(wù)器的性能,考慮到減輕服務(wù)器性能方面,應(yīng)當(dāng)使用cookie剩瓶。
4驹溃、單個(gè)cookie保存的數(shù)據(jù)不能超過(guò)4K,很多瀏覽器都限制一個(gè)站點(diǎn)最多保存20個(gè)cookie延曙。
5、所以個(gè)人建議:
將登陸信息等重要信息存放為session
其他信息如果需要保留亡哄,可以放在cookie中
五.Token 和 Session 的區(qū)別:
session和 token并不矛盾枝缔,作為身份認(rèn)證token安全性比session好,因?yàn)槊總€(gè)請(qǐng)求都有簽名還能防止監(jiān)聽(tīng)以及重放攻擊蚊惯,而session就必須靠鏈路層來(lái)保障通訊安全了愿卸。如上所說(shuō),如果你需要實(shí)現(xiàn)有狀態(tài)的會(huì)話截型,仍然可以增加session來(lái)在服務(wù)器端保存一些狀態(tài)趴荸。
App通常用restful api跟server打交道。Rest是stateless的宦焦,也就是app不需要像browser那樣用cookie來(lái)保存session,因此用session token來(lái)標(biāo)示自己就夠了发钝,session/state由api server的邏輯處理顿涣。如果你的后端不是stateless的rest api,那么你可能需要在app里保存session.可以在app里嵌入webkit,用一個(gè)隱藏的browser來(lái)管理cookie session.
Session是一種HTTP存儲(chǔ)機(jī)制,目的是為無(wú)狀態(tài)的HTTP提供的持久機(jī)制酝豪。所謂Session認(rèn)證只是簡(jiǎn)單的把User信息存儲(chǔ)到Session里涛碑,因?yàn)镾ID的不可預(yù)測(cè)性,暫且認(rèn)為是安全的孵淘。這是一種認(rèn)證手段蒲障。而Token,如果指的是OAuth Token或類似的機(jī)制的話瘫证,提供的是 認(rèn)證 和 授權(quán) 揉阎,認(rèn)證是針對(duì)用戶,授權(quán)是針對(duì)App背捌。
其目的是讓 某App有權(quán)利訪問(wèn) 某用戶 的信息毙籽。這里的Token是唯一的。不可以轉(zhuǎn)移到其它App上载萌,也不可以轉(zhuǎn)到其它 用戶 上惧财。轉(zhuǎn)過(guò)來(lái)說(shuō)Session。Session只提供一種簡(jiǎn)單的認(rèn)證扭仁,即有此SID垮衷,即認(rèn)為有此User的全部權(quán)利。是需要嚴(yán)格保密的乖坠,這個(gè)數(shù)據(jù)應(yīng)該只保存在站方搀突,不應(yīng)該共享給其它網(wǎng)站或者第三方App。所以簡(jiǎn)單來(lái)說(shuō)熊泵,如果你的用戶數(shù)據(jù)可能需要和第三方共享仰迁,或者允許第三方調(diào)用API接口,用Token顽分。如果永遠(yuǎn)只是自己的網(wǎng)站徐许,自己的App,用什么就無(wú)所謂了卒蘸。
token就是令牌雌隅,比如你授權(quán)(登錄)一個(gè)程序時(shí),他就是個(gè)依據(jù)缸沃,判斷你是否已經(jīng)授權(quán)該軟件恰起;cookie就是寫在客戶端的一個(gè)txt文件,里面包括你登錄信息之類的趾牧,這樣你下次在登錄某個(gè)網(wǎng)站检盼,就會(huì)自動(dòng)調(diào)用cookie自動(dòng)登錄用戶名;session和cookie差不多翘单,只是session是寫在服務(wù)器端的文件吨枉,也需要在客戶端寫入cookie文件蹦渣,但是文件里是你的瀏覽器編號(hào).Session的狀態(tài)是存儲(chǔ)在服務(wù)器端,客戶端只有session id东羹;而Token的狀態(tài)是存儲(chǔ)在客戶端剂桥。