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