session、token、jwt、oauth2傻傻分不清
在我們的 java 業(yè)務(wù)系統(tǒng)中,或多或少的會(huì)涉及到權(quán)限、認(rèn)證等類似的概念。但是很多小伙伴還是傻傻的分不清這些的概念和區(qū)別,今天我們就來(lái)好好的捋一捋,將其區(qū)別的概念深深的刻在腦海中。
認(rèn)證 Authentication
百度百科中對(duì)于認(rèn)證的解釋是:身份驗(yàn)證(Authentication),在 .NET Framework 安全中,通過(guò)對(duì)照某些機(jī)構(gòu)檢查用戶的憑據(jù),發(fā)現(xiàn)和驗(yàn)證主體標(biāo)識(shí)的過(guò)程。
當(dāng)然,今天我們來(lái)討論肯定不會(huì)用這么生硬的詞來(lái)解釋的。
- 通俗地講就是 驗(yàn)證當(dāng)前用戶的身份,證明“你是你自己”(比如:你每天上下班打卡,都需要通過(guò)指紋打卡,當(dāng)你的指紋和系統(tǒng)里錄入的指紋相匹配時(shí),就打卡成功)
常見(jiàn)的認(rèn)證方式:
- 用戶名密碼登錄
- 郵箱發(fā)送登錄鏈接
- 手機(jī)號(hào)接收驗(yàn)證碼
- 只要你能收到郵箱/驗(yàn)證碼,就默認(rèn)你是賬號(hào)的主人
授權(quán) Authorization
所謂授權(quán),就是某個(gè)用戶授予其他應(yīng)用訪問(wèn)該用戶某些資源的權(quán)限。
例如,在你安裝手機(jī)應(yīng)用的時(shí)候,APP肯定會(huì)跳出來(lái)問(wèn)是否允許授予權(quán)限(訪問(wèn)相冊(cè)、位置等權(quán)限);你在訪問(wèn)微信小程序時(shí),當(dāng)?shù)卿洉r(shí),小程序會(huì)詢問(wèn)是否允許授予權(quán)限(獲取昵稱、頭像、地區(qū)、性別等個(gè)人信息)
實(shí)現(xiàn)授權(quán)的方式有:cookie、session、token、OAuth
憑證 Credentials
實(shí)現(xiàn)認(rèn)證和授權(quán)的前提是需要一種媒介(證書(shū)) 來(lái)標(biāo)記訪問(wèn)者的身份。
這個(gè)其實(shí)很好理解,身份證大家肯定是都有的。過(guò)身份證,我們可以辦理手機(jī)卡/銀行卡/個(gè)人貸款/交通出行等等,這就是認(rèn)證的憑證。
在互聯(lián)網(wǎng)應(yīng)用中,一般網(wǎng)站會(huì)有兩種模式,游客模式和登錄模式。
- 游客模式下,可以正常瀏覽網(wǎng)站上面的文章,一旦想要點(diǎn)贊/收藏/分享文章,就需要登錄或者注冊(cè)賬號(hào)。
- 登錄模式,當(dāng)用戶登錄成功后,服務(wù)器會(huì)給該用戶使用的瀏覽器頒發(fā)一個(gè)令牌(token),這個(gè)令牌用來(lái)表明你的身份,每次瀏覽器發(fā)送請(qǐng)求時(shí)會(huì)帶上這個(gè)令牌,就可以使用游客模式下無(wú)法使用的功能。
Cookie
HTTP 是無(wú)狀態(tài)的協(xié)議(對(duì)于事務(wù)處理沒(méi)有記憶能力,每次客戶端和服務(wù)端會(huì)話完成時(shí),服務(wù)端不會(huì)保存任何會(huì)話信息):每個(gè)請(qǐng)求都是完全獨(dú)立的,服務(wù)端無(wú)法確認(rèn)當(dāng)前訪問(wèn)者的身份信息,無(wú)法分辨上一次的請(qǐng)求發(fā)送者和這一次的發(fā)送者是不是同一個(gè)人。
所以服務(wù)器與瀏覽器為了進(jìn)行會(huì)話跟蹤(知道是誰(shuí)在訪問(wèn)我),就必須主動(dòng)的去維護(hù)一個(gè)狀態(tài),這個(gè)狀態(tài)用于告知服務(wù)端前后兩個(gè)請(qǐng)求是否來(lái)自同一瀏覽器。而這個(gè)狀態(tài)需要通過(guò) cookie 或者 session 去實(shí)現(xiàn)。
cookie 存儲(chǔ)在客戶端:cookie 是服務(wù)器發(fā)送到用戶瀏覽器并保存在本地的一小塊數(shù)據(jù),它會(huì)在瀏覽器下次向同一服務(wù)器再發(fā)起請(qǐng)求時(shí)被攜帶并發(fā)送到服務(wù)器上。
cookie 是不可跨域的:每個(gè) cookie 都會(huì)綁定單一的域名,無(wú)法在別的域名下獲取使用,一級(jí)域名和二級(jí)域名之間是允許共享使用的(靠的是 domain)。
Session
session 是另外一種記錄服務(wù)器和客戶端會(huì)話狀態(tài)的機(jī)制,通常情況下,session 是基于 cookie 實(shí)現(xiàn)的,session 存儲(chǔ)在服務(wù)器端,sessionId 會(huì)被存儲(chǔ)到客戶端的cookie 中。
session 認(rèn)證流程:
- 用戶第一次請(qǐng)求服務(wù)器的時(shí)候,服務(wù)器根據(jù)用戶提交的相關(guān)信息,創(chuàng)建對(duì)應(yīng)的 Session
- 請(qǐng)求返回時(shí)將此 Session 的唯一標(biāo)識(shí)信息 SessionID 返回給瀏覽器
- 瀏覽器接收到服務(wù)器返回的 SessionID 信息后,會(huì)將此信息存入到 Cookie 中,同時(shí) Cookie 記錄此 SessionID 屬于哪個(gè)域名
- 當(dāng)用戶第二次訪問(wèn)服務(wù)器的時(shí)候,請(qǐng)求會(huì)自動(dòng)判斷此域名下是否存在 Cookie 信息,如果存在自動(dòng)將 Cookie 信息也發(fā)送給服務(wù)端,服務(wù)端會(huì)從 Cookie 中獲取 SessionID,再根據(jù) SessionID 查找對(duì)應(yīng)的 Session 信息,如果沒(méi)有找到說(shuō)明用戶沒(méi)有登錄或者登錄失效,如果找到 Session 證明用戶已經(jīng)登錄可執(zhí)行后面操作。
目前,大部分系統(tǒng)都是根據(jù)此原理來(lái)驗(yàn)證用戶的登錄狀態(tài)的。
Cookie 和 Session 的區(qū)別
這個(gè)應(yīng)該是面試中問(wèn)的頻率非常高的一個(gè)問(wèn)題了。
- 安全性:Session 比 Cookie 安全,Session 是存儲(chǔ)在服務(wù)器端的,Cookie 是存儲(chǔ)在客戶端的。
- 存取值的類型不同:Cookie 只支持存字符串?dāng)?shù)據(jù),想要設(shè)置其他類型的數(shù)據(jù),需要將其轉(zhuǎn)換成字符串,Session 可以存任意數(shù)據(jù)類型。
- 有效期不同:Cookie 可設(shè)置為長(zhǎng)時(shí)間保持,比如我們經(jīng)常使用的默認(rèn)登錄功能,Session 一般失效時(shí)間較短,客戶端關(guān)閉(默認(rèn)情況下)或者 Session 超時(shí)都會(huì)失效。
- 存儲(chǔ)大小不同:?jiǎn)蝹€(gè) Cookie 保存的數(shù)據(jù)不能超過(guò) 4K,Session 可存儲(chǔ)數(shù)據(jù)遠(yuǎn)高于 Cookie,但是當(dāng)訪問(wèn)量過(guò)多,會(huì)占用過(guò)多的服務(wù)器資源。
令牌 Token
Acesss Token
訪問(wèn)資源接口(API)時(shí)所需要的資源憑證,簡(jiǎn)單 token 的組成:uid(用戶唯一的身份標(biāo)識(shí))、time(當(dāng)前時(shí)間的時(shí)間戳)、sign(簽名,token 的前幾位以哈希算法壓縮成的一定長(zhǎng)度的十六進(jìn)制字符串)
Acesss Token的特點(diǎn)是 * 服務(wù)端無(wú)狀態(tài)化、可擴(kuò)展性好 * 支持移動(dòng)端設(shè)備 * 安全 * 支持跨程序調(diào)用
token 的身份驗(yàn)證流程如下:
- 客戶端使用用戶名跟密碼請(qǐng)求登錄
- 服務(wù)端收到請(qǐng)求,去驗(yàn)證用戶名與密碼
- 驗(yàn)證成功后,服務(wù)端會(huì)簽發(fā)一個(gè) token 并把這個(gè) token 發(fā)送給客戶端
- 客戶端收到 token 以后,會(huì)把它存儲(chǔ)起來(lái),比如放在 cookie 里或者 localStorage 里
- 客戶端每次向服務(wù)端請(qǐng)求資源的時(shí)候需要帶著服務(wù)端簽發(fā)的 token
- 服務(wù)端收到請(qǐng)求,然后去驗(yàn)證客戶端請(qǐng)求里面帶著的 token ,如果驗(yàn)證成功,就向客戶端返回請(qǐng)求的數(shù)據(jù)
Refresh Token
refresh token 是專用于刷新 access token 的 token。
如果沒(méi)有 refresh token,也可以刷新 access token,但每次刷新都要用戶輸入登錄用戶名與密碼,會(huì)很麻煩。有了 refresh token,可以減少這個(gè)麻煩,客戶端直接用 refresh token 去更新 access token,無(wú)需用戶進(jìn)行額外的操作。
Access Token 的有效期比較短,當(dāng) Acesss Token 由于過(guò)期而失效時(shí),使用 Refresh Token 就可以獲取到新的 Token,如果 Refresh Token 也失效了,用戶就只能重新登錄了。
Refresh Token 及過(guò)期時(shí)間是存儲(chǔ)在服務(wù)器的數(shù)據(jù)庫(kù)中,只有在申請(qǐng)新的 Acesss Token 時(shí)才會(huì)驗(yàn)證,不會(huì)對(duì)業(yè)務(wù)接口響應(yīng)時(shí)間造成影響,也不需要向 Session 一樣一直保持在內(nèi)存中以應(yīng)對(duì)大量的請(qǐng)求。
Token 和 Session 的區(qū)別
Session 是一種記錄服務(wù)器和客戶端會(huì)話狀態(tài)的機(jī)制,使服務(wù)端有狀態(tài)化,可以記錄會(huì)話信息。而 Token 是令牌,訪問(wèn)資源接口(API)時(shí)所需要的資源憑證。Token 使服務(wù)端無(wú)狀態(tài)化,不會(huì)存儲(chǔ)會(huì)話信息。
Session 和 Token 并不矛盾,作為身份認(rèn)證 Token 安全性比 Session 好,因?yàn)槊恳粋€(gè)請(qǐng)求都有簽名還能防止監(jiān)聽(tīng)以及重放攻擊,而 Session 就必須依賴鏈路層來(lái)保障通訊安全了。如果你需要實(shí)現(xiàn)有狀態(tài)的會(huì)話,仍然可以增加 Session 來(lái)在服務(wù)器端保存一些狀態(tài)。
所謂 Session 認(rèn)證只是簡(jiǎn)單的把 User 信息存儲(chǔ)到 Session 里,因?yàn)?SessionID 的不可預(yù)測(cè)性,暫且認(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)到其它用戶上。Session 只提供一種簡(jiǎn)單的認(rèn)證,即只要有此 SessionID ,即認(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ú)所謂了。
JWT(JSON Web Token)
JSON Web Token(簡(jiǎn)稱 JWT)是目前最流行的跨域認(rèn)證解決方案
JWT 是為了在網(wǎng)絡(luò)應(yīng)用環(huán)境間傳遞聲明而執(zhí)行的一種基于 JSON 的開(kāi)放標(biāo)準(zhǔn)(RFC 7519)。JWT 的聲明一般被用來(lái)在身份提供者和服務(wù)提供者間傳遞被認(rèn)證的用戶身份信息,以便于從資源服務(wù)器獲取資源。比如用在用戶登錄上。
可以使用 HMAC 算法或者是 RSA 的公/私秘鑰對(duì) JWT 進(jìn)行簽名。因?yàn)閿?shù)字簽名的存在,這些傳遞的信息是可信的。
JWT 認(rèn)證流程:
- 用戶輸入用戶名/密碼登錄,服務(wù)端認(rèn)證成功后,會(huì)返回給客戶端一個(gè) JWT
- 客戶端將 token 保存到本地(通常使用 localstorage,也可以使用 cookie)
- 當(dāng)用戶希望訪問(wèn)一個(gè)受保護(hù)的路由或者資源的時(shí)候,需要請(qǐng)求頭的 Authorization 字段中使用Bearer 模式添加 JWT