前端登錄,這一篇就夠了
登錄是每個(gè)網(wǎng)站中都經(jīng)常用到的一個(gè)功能,在頁(yè)面上我們輸入賬號(hào)密碼,敲一下回車鍵,就登錄了,但這背后的登錄原理你是否清楚呢?今天我們就來介紹幾種常用的登錄方式。
Cookie + Session 登錄 Token 登錄 SSO 單點(diǎn)登錄 OAuth 第三方登錄
Cookie + Session 登錄
HTTP 是一種無狀態(tài)的協(xié)議,客戶端每次發(fā)送請(qǐng)求時(shí),首先要和服務(wù)器端建立一個(gè)連接,在請(qǐng)求完成后又會(huì)斷開這個(gè)連接。這種方式可以節(jié)省傳輸時(shí)占用的連接資源,但同時(shí)也存在一個(gè)問題:每次請(qǐng)求都是獨(dú)立的,服務(wù)器端無法判斷本次請(qǐng)求和上一次請(qǐng)求是否來自同一個(gè)用戶,進(jìn)而也就無法判斷用戶的登錄狀態(tài)。
為了解決 HTTP 無狀態(tài)的問題,Lou Montulli 在 1994 年的時(shí)候,推出了 Cookie。
Cookie 是服務(wù)器端發(fā)送給客戶端的一段特殊信息,這些信息以文本的方式存放在客戶端,客戶端每次向服務(wù)器端發(fā)送請(qǐng)求時(shí)都會(huì)帶上這些特殊信息。
有了 Cookie 之后,服務(wù)器端就能夠獲取到客戶端傳遞過來的信息了,如果需要對(duì)信息進(jìn)行驗(yàn)證,還需要通過 Session。
客戶端請(qǐng)求服務(wù)端,服務(wù)端會(huì)為這次請(qǐng)求開辟一塊內(nèi)存空間,這個(gè)便是 Session 對(duì)象。
有了 Cookie 和 Session 之后,我們就可以進(jìn)行登錄認(rèn)證了。
Cookie + Session ?實(shí)現(xiàn)流程
Cookie + Session 的登錄方式是最經(jīng)典的一種登錄方式,現(xiàn)在仍然有大量的企業(yè)在使用。
用戶首次登錄時(shí):

用戶訪問 a.com/pageA,并輸入密碼登錄。服務(wù)器驗(yàn)證密碼無誤后,會(huì)創(chuàng)建 SessionId,并將它保存起來。 服務(wù)器端響應(yīng)這個(gè) HTTP 請(qǐng)求,并通過 Set-Cookie 頭信息,將 SessionId 寫入 Cookie 中。
服務(wù)器端的 SessionId 可能存放在很多地方,例如:內(nèi)存、文件、數(shù)據(jù)庫(kù)等。
第一次登錄完成之后,后續(xù)的訪問就可以直接使用 Cookie 進(jìn)行身份驗(yàn)證了:

用戶訪問 a.com/pageB頁(yè)面時(shí),會(huì)自動(dòng)帶上第一次登錄時(shí)寫入的 Cookie。服務(wù)器端比對(duì) Cookie 中的 SessionId 和保存在服務(wù)器端的 SessionId 是否一致。 如果一致,則身份驗(yàn)證成功。
Cookie + Session ?存在的問題
雖然我們使用 Cookie + Session ?的方式完成了登錄驗(yàn)證,但仍然存在一些問題:
由于服務(wù)器端需要對(duì)接大量的客戶端,也就需要存放大量的 SessionId,這樣會(huì)導(dǎo)致服務(wù)器壓力過大。 如果服務(wù)器端是一個(gè)集群,為了同步登錄態(tài),需要將 SessionId 同步到每一臺(tái)機(jī)器上,無形中增加了服務(wù)器端維護(hù)成本。 由于 SessionId 存放在 Cookie 中,所以無法避免 CSRF 攻擊。
Token 登錄
為了解決 Session + Cookie 機(jī)制暴露出的諸多問題,我們可以使用 Token 的登錄方式。
Token 是服務(wù)端生成的一串字符串,以作為客戶端請(qǐng)求的一個(gè)令牌。當(dāng)?shù)谝淮蔚卿浐?,服?wù)器會(huì)生成一個(gè) Token 并返回給客戶端,客戶端后續(xù)訪問時(shí),只需帶上這個(gè) Token 即可完成身份認(rèn)證。
Token 機(jī)制實(shí)現(xiàn)流程
用戶首次登錄時(shí):

用戶輸入賬號(hào)密碼,并點(diǎn)擊登錄。 服務(wù)器端驗(yàn)證賬號(hào)密碼無誤,創(chuàng)建 Token。 服務(wù)器端將 Token 返回給客戶端,由***客戶端自由保存***。
后續(xù)頁(yè)面訪問時(shí):

用戶訪問 a.com/pageB時(shí),帶上第一次登錄時(shí)獲取的 Token。服務(wù)器端驗(yàn)證 Token ,有效則身份驗(yàn)證成功。
Token 機(jī)制的特點(diǎn)
根據(jù)上面的案例,我們可以分析出 Token 的優(yōu)缺點(diǎn):
服務(wù)器端不需要存放 Token,所以不會(huì)對(duì)服務(wù)器端造成壓力,即使是服務(wù)器集群,也不需要增加維護(hù)成本。 Token 可以存放在前端任何地方,可以不用保存在 Cookie 中,提升了頁(yè)面的安全性。 Token 下發(fā)之后,只要在生效時(shí)間之內(nèi),就一直有效,如果服務(wù)器端想收回此 Token 的權(quán)限,并不容易。
Token 的生成方式
最常見的 Token 生成方式是使用 JWT(Json Web Token),它是一種簡(jiǎn)潔的,自包含的方法用于通信雙方之間以 JSON 對(duì)象的形式安全的傳遞信息。
上文中我們說到,使用 Token 后,服務(wù)器端并不會(huì)存儲(chǔ) Token,那怎么判斷客戶端發(fā)過來的 Token 是合法有效的呢?
答案其實(shí)就在 Token 字符串中,其實(shí) Token 并不是一串雜亂無章的字符串,而是通過多種算法拼接組合而成的字符串,我們來具體分析一下。
JWT 算法主要分為 3 個(gè)部分:header(頭信息),playload(消息體),signature(簽名)。
header 部分指定了該 JWT 使用的簽名算法:
header?=?'{"alg":"HS256","typ":"JWT"}'???//?`HS256`?表示使用了 HMAC-SHA256 來生成簽名。
playload 部分表明了 JWT 的意圖:
payload?=?'{"loggedInAs":"admin","iat":1422779638}'?????//iat?表示令牌生成的時(shí)間
signature 部分為 JWT 的簽名,主要為了讓 JWT 不能被隨意篡改,簽名的方法分為兩個(gè)步驟:
輸入 base64url編碼的 header 部分、.、base64url編碼的 playload 部分,輸出 unsignedToken。輸入服務(wù)器端私鑰、unsignedToken,輸出 signature 簽名。
const?base64Header?=?encodeBase64(header)
const?base64Payload?=?encodeBase64(payload)
const?unsignedToken?=?`${base64Header}.${base64Payload}`
const?key?=?'服務(wù)器私鑰'
signature?=?HMAC(key,?unsignedToken)
最后的 Token 計(jì)算如下:
const?base64Header?=?encodeBase64(header)
const?base64Payload?=?encodeBase64(payload)
const?base64Signature?=?encodeBase64(signature)
token?=?`${base64Header}.${base64Payload}.${base64Signature}`
服務(wù)器在判斷 Token 時(shí):
const?[base64Header,?base64Payload,?base64Signature]?=?token.split('.')
const?signature1?=?decodeBase64(base64Signature)
const?unsignedToken?=?`${base64Header}.${base64Payload}`
const?signature2?=?HMAC('服務(wù)器私鑰',?unsignedToken)
if(signature1?===?signature2)?{
??return?'簽名驗(yàn)證成功,token?沒有被篡改'
}
const?payload?=??decodeBase64(base64Payload)
if(new?Date()?-?payload.iat?'token?有效期'){
??return?'token?有效'
}
有了 Token 之后,登錄方式已經(jīng)變得非常高效,接下來我們介紹另外兩種登錄方式。
SSO 單點(diǎn)登錄
單點(diǎn)登錄指的是在公司內(nèi)部搭建一個(gè)公共的認(rèn)證中心,公司下的所有產(chǎn)品的登錄都可以在認(rèn)證中心里完成,一個(gè)產(chǎn)品在認(rèn)證中心登錄后,再去訪問另一個(gè)產(chǎn)品,可以不用再次登錄,即可獲取登錄狀態(tài)。
SSO 機(jī)制實(shí)現(xiàn)流程
用戶首次訪問時(shí),需要在認(rèn)證中心登錄:

用戶訪問網(wǎng)站 ? a.com下的 pageA 頁(yè)面。由于沒有登錄,則會(huì)重定向到認(rèn)證中心,并帶上回調(diào)地址 www.sso.com?return_uri=a.com/pageA,以便登錄后直接進(jìn)入對(duì)應(yīng)頁(yè)面。用戶在認(rèn)證中心輸入賬號(hào)密碼,提交登錄。 認(rèn)證中心驗(yàn)證賬號(hào)密碼有效,然后重定向 ? a.com?ticket=123帶上授權(quán)碼 ticket,并將認(rèn)證中心sso.com的登錄態(tài)寫入 Cookie。在 a.com服務(wù)器中,拿著 ticket 向認(rèn)證中心確認(rèn),授權(quán)碼 ticket 真實(shí)有效。驗(yàn)證成功后,服務(wù)器將登錄信息寫入 Cookie(此時(shí)客戶端有 2 個(gè) Cookie 分別存有 a.com和sso.com的登錄態(tài))。
認(rèn)證中心登錄完成之后,繼續(xù)訪問 a.com 下的其他頁(yè)面:

這個(gè)時(shí)候,由于 a.com 存在已登錄的 Cookie 信息,所以服務(wù)器端直接認(rèn)證成功。
如果認(rèn)證中心登錄完成之后,訪問 b.com 下的頁(yè)面:

這個(gè)時(shí)候,由于認(rèn)證中心存在之前登錄過的 Cookie,所以也不用再次輸入賬號(hào)密碼,直接返回第 4 步,下發(fā) ticket 給 b.com 即可。
SSO 單點(diǎn)登錄退出
目前我們已經(jīng)完成了單點(diǎn)登錄,在同一套認(rèn)證中心的管理下,多個(gè)產(chǎn)品可以共享登錄態(tài)?,F(xiàn)在我們需要考慮退出了,即:在一個(gè)產(chǎn)品中退出了登錄,怎么讓其他的產(chǎn)品也都退出登錄?
原理其實(shí)不難,可以回過頭來看第 5 步,每一個(gè)產(chǎn)品在向認(rèn)證中心驗(yàn)證 ticket 時(shí),其實(shí)可以順帶將自己的退出登錄 api 發(fā)送到認(rèn)證中心。
當(dāng)某個(gè)產(chǎn)品 c.com 退出登錄時(shí):
清空 c.com中的登錄態(tài) Cookie。請(qǐng)求認(rèn)證中心 sso.com中的退出 api。認(rèn)證中心遍歷下發(fā)過 ticket 的所有產(chǎn)品,并調(diào)用對(duì)應(yīng)的退出 api,完成退出。
OAuth 第三方登錄
在上文中,我們使用單點(diǎn)登錄完成了多產(chǎn)品的登錄態(tài)共享,但都是建立在一套統(tǒng)一的認(rèn)證中心下,對(duì)于一些小型企業(yè),未免太麻煩,有沒有一種登錄能夠做到開箱即用?
其實(shí)是有的,很多大廠都會(huì)提供自己的第三方登錄服務(wù),我們一起來分析一下。

OAuth 機(jī)制實(shí)現(xiàn)流程
這里以微信開放平臺(tái)的接入流程為例:

首先, a.com的運(yùn)營(yíng)者需要在微信開放平臺(tái)注冊(cè)賬號(hào),并向微信申請(qǐng)使用微信登錄功能。申請(qǐng)成功后,得到申請(qǐng)的 appid、appsecret。 用戶在 a.com上選擇使用微信登錄。這時(shí)會(huì)跳轉(zhuǎn)微信的 OAuth 授權(quán)登錄,并帶上 a.com的回調(diào)地址。用戶輸入微信賬號(hào)和密碼,登錄成功后,需要選擇具體的授權(quán)范圍,如:授權(quán)用戶的頭像、昵稱等。 授權(quán)之后,微信會(huì)根據(jù)拉起 a.com?code=123,這時(shí)帶上了一個(gè)臨時(shí)票據(jù) code。獲取 code 之后, a.com會(huì)拿著 code 、appid、appsecret,向微信服務(wù)器申請(qǐng) token,驗(yàn)證成功后,微信會(huì)下發(fā)一個(gè) token。有了 token 之后, a.com就可以憑借 token 拿到對(duì)應(yīng)的微信用戶頭像,用戶昵稱等信息了。a.com提示用戶登錄成功,并將登錄狀態(tài)寫入 Cooke,以作為后續(xù)訪問的憑證。
總結(jié)
本文介紹了 4 種常見的登錄方式,原理應(yīng)該大家都清楚了,總結(jié)一下這 4 種方案的使用場(chǎng)景:
Cookie + Session 歷史悠久,適合于簡(jiǎn)單的后端架構(gòu),需開發(fā)人員自己處理好安全問題。 Token 方案對(duì)后端壓力小,適合大型分布式的后端架構(gòu),但已分發(fā)出去的 token ,如果想收回權(quán)限,就不是很方便了。 SSO 單點(diǎn)登錄,適用于中大型企業(yè),想要統(tǒng)一內(nèi)部所有產(chǎn)品的登錄方式。 OAuth 第三方登錄,簡(jiǎn)單易用,對(duì)用戶和開發(fā)者都友好,但第三方平臺(tái)很多,需要選擇合適自己的第三方登錄平臺(tái)。
