前端需知道的常見登錄鑒權(quán)方案
背景
說起鑒權(quán)大家應(yīng)該都很熟悉,不過作為前端開發(fā)來講,鑒權(quán)的流程大頭都在后端小哥那邊,本文的目的就是為了讓大家了解一下常見的鑒權(quán)的方式和原理。
認知:HTTP 是一個無狀態(tài)協(xié)議,所以客戶端每次發(fā)出請求時,下一次請求無法得知上一次請求所包含的狀態(tài)數(shù)據(jù)。
一、HTTP Auth Authentication
簡介
HTTP 提供一個用于權(quán)限控制和認證的通用框架。最常用的HTTP認證方案是HTTP Basic Authentication
鑒權(quán)流程
加解密過程
// Authorization 加密過程
let?email?=?"[email protected]"
let?password?=?"12345678"
let?auth?=?`${email}:${password}`
const?buf?=?Buffer.from(auth,?'ascii');
console.info(buf.toString('base64'));?// cG9zdG1haWxAdGVzdC5jb206MTIzNDU2Nzg=
// Authorization 解密過程
const?buf?=?Buffer.from(authorization.split(' ')[1]?||?''),?'base64');
const?user?=?buf.toString('ascii').split(':');
其他 HTTP 認證
通用 HTTP 身份驗證框架有多個驗證方案使用。不同的驗證方案會在安全強度上有所不同。
IANA 維護了一系列的驗證方案[1],除此之外還有其他類型的驗證方案由虛擬主機服務(wù)提供,例如 Amazon AWS ,常見的驗證方案包括:
Basic ( RFC 7617[2], Base64 編碼憑證. 詳情請參閱下文.),
Bearer ( RFC 6750[3], bearer 令牌通過OAuth 2.0保護資源),
Digest ( RFC 7616[4], 只有 md5 散列 在Firefox中支持, 查看 bug 472823[5] 用于SHA加密支持),
HOBA ( RFC 7486[6] (草案), HTTP Origin-Bound 認證, 基于數(shù)字簽名),
Mutual ( draft-ietf-httpauth-mutual[7]),
AWS4-HMAC-SHA256 ( AWS docs[8])
二、Cookie + Session
注冊流程
思考:為什么要在密碼里加點“鹽”?[9]
鑒權(quán)流程
Session 存儲
最常用的 Session 存儲方式是 KV 存儲,如Redis,在分布式、API 支持、性能方面都是比較好的,除此之外還有 mysql、file 存儲。
如果服務(wù)是分布式的,使用 file 存儲,多個服務(wù)間存在同步 session 的問題;高并發(fā)情況下錯誤讀寫鎖的控制。
Session Refresh
我們上面提到的流程中,缺少 Session 的刷新的環(huán)節(jié),我們不能在用戶登錄之后經(jīng)過一個 expires 時間就把用戶踢出去,如果在 Session 有效期間用戶一直在操作,這時候 expires 時間就應(yīng)該刷新。
以 Koa 為例,刷新 Session 的機制也比較簡單:
開發(fā)一個 middleware(默認情況下所有請求都會經(jīng)過該 middleware),如果校驗 Session 有效,就更新 Session 的 expires: 當前時間+過期時間。
優(yōu)化:
頻繁更新 session 會影響性能,可以在 session 快過期的時候再更新過期時間。
如果某個用戶一直在操作,同一個 sessionID 可能會長期有效,如果相關(guān) cookie 泄露,可能導(dǎo)致比較大的風險,可以在生成 sessionID 的同時生成一個 refreshID,在 sessionID 過期之后使用 refreshID 請求服務(wù)端生成新的 sessionID(這個方案需要前端判斷 sessionID 失效,并攜帶 refreshID 發(fā)請求)。
單設(shè)備登錄
有些情況下,只允許一個帳號在一個端下登錄,如果換了一個端,需要把之前登錄的端踢下線(默認情況下,同一個帳號可以在不同的端下同時登錄的)。
這時候可以借助一個服務(wù)保存用戶唯一標識和 sessionId 值的對應(yīng)關(guān)系,如果同一個用戶,但 sessionId 不一樣,則不允許登錄或者把之前的踢下線(刪除舊 session )。
三、JWT
簡介
JSON Web Token (JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對象在各方之間安全地傳輸信息。該信息可以被驗證和信任,因為它是數(shù)字簽名的。
JWT 組成
JWT 由三部分組成,分別是 header(頭部),payload(載荷),signature(簽證) 這三部分以小數(shù)點連接起來。
例如使用名為 jwt-token 的cookie來存儲 JWT 例如:
jwt-token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibHVzaGlqaWUiLCJpYXQiOjE1MzI1OTUyNTUsImV4cCI6MTUzMjU5NTI3MH0.WZ9_poToN9llFFUfkswcpTljRDjF4JfZcmqYS0JcKO8;
使用.分割值可以得到三部分組成元素,按照順序分別為:
header:
值:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Base64 解碼: {"alg": "HS256", "type": "JWT"}
payload:
值:eyJuYW1lIjoibHVzaGlqaWUiLCJpYXQiOjE1MzI1OTUyNTUsImV4cCI6MTUzMjU5NTI3MH0
Base64 解碼:
{
"name":?"lushijie",
"iat":?1532595255,?// 發(fā)布時間
"exp":?1532595270?// 過期時間
}
signature:
值:WZ9_poToN9llFFUfkswcpTljRDjF4JfZcmqYS0JcKO8
解碼:
const?headerEncode?=?base64Encode(header);
const?payloadEncode?=?base64Encode(payload);
let?signature?=?HMACSHA256(headerEncode?+?'.'?+?payloadEncode,?'密鑰');
鑒權(quán)流程
Token 校驗
對于驗證一個 JWT 是否有效也是比較簡單的,服務(wù)端根據(jù)前面介紹的計算方法計算出 signature,和要校驗的JWT中的 signature 部分進行對比就可以了,如果 signature 部分相等則是一個有效的 JWT。
Token Refresh
為了減少 JWT Token 泄露風險,一般有效期會設(shè)置的比較短。這樣就會存在 JWT Token 過期的情況,我們不可能讓用戶頻繁去登錄獲取新的 JWT Token。
解決方案:
可以同時生成 JWT Token 與 Refresh Token,其中 Refresh Roken 的有效時間長于 JWT Token,這樣當 JWT Token 過期之后,使用 Refresh Token 獲取新的 JWT Token 與 Refresh Token,其中 Refresh Token 只能使用一次。
四、OAuth
簡介
有時候,我們登錄某個網(wǎng)站,但我們又不想注冊該網(wǎng)站的賬號,這時我們可以使用第三方賬號登錄,比如 github、微博、微信、QQ等。
授權(quán)流程
名詞解釋:
Third-party application:第三方應(yīng)用程序又稱"客戶端"(client),比如打開知乎,使用第三方登錄,選擇 Github 登錄,這時候知乎就是客戶端。
Resource Owner:資源所有者,本文中又稱"用戶"(user),即登錄用戶。
Authorization server:認證服務(wù)器,即 Github 專門用來處理認證的服務(wù)器。
Resource server:資源服務(wù)器,即 Github 存放用戶生成的資源的服務(wù)器。它與認證服務(wù)器,可以是同一臺服務(wù)器,也可以是不同的服務(wù)器。
A. A網(wǎng)站讓用戶跳轉(zhuǎn)到 GitHub,請求授權(quán)碼;GitHub 要求用戶登錄,然后詢問“知乎網(wǎng)站要求獲得 xx 權(quán)限,你是否同意?”;
B. 用戶同意,GitHub 就會重定向回 A 網(wǎng)站,同時發(fā)回一個授權(quán)碼;
C. A 網(wǎng)站使用授權(quán)碼,向 GitHub 請求令牌;
D. GitHub 返回令牌;
E. A 網(wǎng)站使用令牌,向 GitHub 請求用戶數(shù)據(jù);
其他授權(quán)模式
授權(quán)碼模式(authorization code)是功能最完整、流程最嚴密的授權(quán)模式。除了我們上面所說的授權(quán)碼模式,其實還有其他授權(quán)模式:
簡化模式(Implicit grant type)
有些 Web 應(yīng)用是純前端應(yīng)用,沒有后端。這時就不能用上面的方式了,必須將令牌儲存在前端。RFC 6749 就規(guī)定了第二種方式,允許直接向前端頒發(fā)令牌。這種方式?jīng)]有授權(quán)碼這個中間步驟
密碼模式(Resource Owner Password Credentials Grant)
如果你高度信任某個應(yīng)用,RFC 6749 也允許用戶把用戶名和密碼,直接告訴該應(yīng)用。該應(yīng)用就使用你的密碼,申請令牌
客戶端模式(Client Credentials Grant)
適用于沒有前端的命令行應(yīng)用,即在命令行下請求令牌
關(guān)于這些模式詳細請見:OAuth2.0 的四種方式[10]
單點登錄
單點登錄(Single Sign On, SSO),即:單一標記(單點)登錄。例如:QQ,我在QQ空間登錄一次,我可以去訪問QQ產(chǎn)品的其他服務(wù):QQ郵箱、騰訊新聞等,都能保證你的賬戶保持登錄狀態(tài)。
延伸閱讀:
《如何實現(xiàn)單點登錄?》[11]
《手機掃碼登錄內(nèi)網(wǎng)怎么實現(xiàn)的?》[12]
五、總結(jié)對比
沒有最好,只有最合適!!!
HTTP Auth Authentication:
梳理總結(jié):
通用 HTTP 身份驗證框架有多個驗證方案使用。不同的驗證方案會在安全強度上有所不同。HTTP Auth Authentication 是最常用的 HTTP認證方案,為了減少泄露風險一般要求 HTTPS 協(xié)議。
適用場景:
一般多被用在內(nèi)部安全性要求不高的的系統(tǒng)上,如路由器網(wǎng)頁管理接口
問題:
請求上攜帶驗證信息,容易被嗅探到
無法注銷
適合一次性驗證,例如注冊激活鏈接
Cookie + Session:
梳理總結(jié):
服務(wù)端存儲 session ,客戶端存儲 cookie,其中 cookie 保存的為 sessionID
可以靈活 revoke 權(quán)限,更新信息后可以方便的同步 session 中相應(yīng)內(nèi)容
分布式 session 一般使用 redis(或其他KV) 存儲
使用場景:
適合傳統(tǒng)系統(tǒng)獨立鑒權(quán)
JWT:
梳理總結(jié):
服務(wù)器不再需要存儲 session,服務(wù)器認證鑒權(quán)業(yè)務(wù)可以方便擴展
JWT 并不依賴 cookie,也可以使用 header 傳遞
為減少盜用,要使用 HTTPS 協(xié)議傳輸
適用場景:
適合做簡單的 RESTful API 認證
適合一次性驗證,例如注冊激活鏈接
問題:
使用過程中無法廢棄某個 token,有效期內(nèi) token 一直有效
payload 信息更新時,已下發(fā)的 token 無法同步
OAuth:
梳理總結(jié):
OAuth是一個開放標準,允許用戶授權(quán)第三方應(yīng)用訪問他們存儲在另外的服務(wù)提供者上的信息,而不需要將用戶名和密碼提供給第三方移動應(yīng)用或分享他們數(shù)據(jù)的所有內(nèi)容。
GitHub OAuth 文檔 Identifying and authorizing users for GitHub Apps
適用場景:
OAuth 分為下面四種模式:
簡化模式,不安全,適用于純靜態(tài)頁面應(yīng)用
授權(quán)碼模式,功能最完整、流程最嚴密的授權(quán)模式,通常使用在公網(wǎng)的開放平臺中
密碼模式,一般在內(nèi)部系統(tǒng)中使用,調(diào)用者是以用戶為單位。
客戶端模式,一般在內(nèi)部系統(tǒng)之間的 API 調(diào)用。兩個平臺之間調(diào)用,以平臺為單位。
文內(nèi)鏈接:
1.一系列的驗證方案:
http://www.iana.org/assignments/http-authschemes/http-authschemes.xhtml
2.RFC 7617:
https://tools.ietf.org/html/rfc7617
3.RFC 6750:
https://tools.ietf.org/html/rfc6750
4.RFC 6716:
https://link.zhihu.com/?target=https%3A//tools.ietf.org/html/rfc6750
5.bug 472823:
https://bugzilla.mozilla.org/show_bug.cgi?id=472823
6.RFC 7486:
https://tools.ietf.org/html/rfc7486
7.draft-ietf-httpauth-mutual:
https://tools.ietf.org/html/draft-ietf-httpauth-mutual-11
8.AWS docs:
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-auth-using-authorization-header.html
9.為什么要在密碼里加點“鹽”?
https://www.cnblogs.com/apolloren/p/11985083.html
10.OAuth2.0 的四種方式:
http://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html
11.如何實現(xiàn)單點登錄?:
https://blog.csdn.net/Faker_Wang/article/details/80877654
11.手機掃碼登錄內(nèi)網(wǎng)怎么實現(xiàn)的?:
https://blog.csdn.net/maxchenBug/article/details/88791514
??愛心三連擊
1.看到這里了就點個在看支持下吧,你的「點贊,在看」是我創(chuàng)作的動力。
2.關(guān)注公眾號
程序員成長指北,回復(fù)「1」加入Node進階交流群!「在這里有好多 Node 開發(fā)者,會討論 Node 知識,互相學(xué)習(xí)」!3.也可添加微信【ikoala520】,一起成長。
“在看轉(zhuǎn)發(fā)”是最大的支持








