微服務(wù)架構(gòu)下的鑒權(quán),怎么做更優(yōu)雅?
點擊上方藍色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時間送達
作者 | code301
來源 | urlify.cn/INBnEj
一、單體應(yīng)用 VS 微服務(wù)
二、微服務(wù)常見安全認證方案
HTTP 基本認證
客戶端發(fā)送 HTTP Request 給服務(wù)器。
因為 Request 中沒有包含 Authorization header,服務(wù)器會返回一個 401 Unauthozied 給客戶端,并且在 Response 的 Header "WWW-Authenticate" 中添加信息。
客戶端把用戶名和密碼用 BASE64 加密后,放在 Authorization Header 中發(fā)送給服務(wù)器, 認證成功。
服務(wù)器將 Authorization Header 中的用戶名密碼取出,進行驗證, 如果驗證通過,將根據(jù)請求,發(fā)送資源給客戶端。
基于 Session 的認證
基于 Session 的認證應(yīng)該是最常用的一種認證機制了。用戶登錄認證成功后,將用戶相關(guān)數(shù)據(jù)存儲到 Session 中,單體應(yīng)用架構(gòu)中,默認 Session 會存儲在應(yīng)用服務(wù)器中,并且將 Session ID 返回到客戶端,存儲在瀏覽器的 Cookie 中。
但是在分布式架構(gòu)下,Session 存放于某個具體的應(yīng)用服務(wù)器中自然就無法滿足使用了,簡單的可以通過 Session 復(fù)制或者 Session 粘制的方案來解決。
Session 復(fù)制依賴于應(yīng)用服務(wù)器,需要應(yīng)用服務(wù)器有 Session 復(fù)制能力,不過現(xiàn)在大部分應(yīng)用服務(wù)器如 Tomcat、JBoss、WebSphere 等都已經(jīng)提供了這個能力。
除此之外,Session 復(fù)制的一大缺陷在于當(dāng)節(jié)點數(shù)比較多時,大量的 Session 數(shù)據(jù)復(fù)制會占用較多網(wǎng)絡(luò)資源。Session 粘滯是通過負載均衡器,將統(tǒng)一用戶的請求都分發(fā)到固定的服務(wù)器節(jié)點上,這樣就保證了對某一用戶而言,Session 數(shù)據(jù)始終是正確的。不過這種方案依賴于負載均衡器,并且只能滿足水平擴展的集群場景,無法滿足應(yīng)用分割后的分布式場景。
在微服務(wù)架構(gòu)下,每個微服務(wù)拆分的粒度會很細,并且不只有用戶和微服務(wù)打交道,更多還有微服務(wù)間的調(diào)用。這個時候上述兩個方案都無法滿足,就要求必須要將 Session 從應(yīng)用服務(wù)器中剝離出來,存放在外部進行集中管理??梢允菙?shù)據(jù)庫,也可以是分布式緩存,如 Memchached、Redis 等。這正是 David Borsos 建議的第二種方案,分布式 Session 方案。
基于 Token 的認證
用戶輸入登錄信息(或者調(diào)用 Token 接口,傳入用戶信息),發(fā)送到身份認證服務(wù)進行認證(身份認證服務(wù)可以和服務(wù)端在一起,也可以分離,看微服務(wù)拆分情況了)。
身份驗證服務(wù)驗證登錄信息是否正確,返回接口(一般接口中會包含用戶基礎(chǔ)信息、權(quán)限范圍、有效時間等信息),客戶端存儲接口,可以存儲在 Session 或者數(shù)據(jù)庫中。
用戶將 Token 放在 HTTP 請求頭中,發(fā)起相關(guān) API 調(diào)用。
被調(diào)用的微服務(wù),驗證 Token 權(quán)限。
服務(wù)端返回相關(guān)資源和數(shù)據(jù)。
服務(wù)端無狀態(tài):Token 機制在服務(wù)端不需要存儲 session 信息,因為 Token 自身包含了所有用戶的相關(guān)信息。
性能較好,因為在驗證 Token 時不用再去訪問數(shù)據(jù)庫或者遠程服務(wù)進行權(quán)限校驗,自然可以提升不少性能。
支持移動設(shè)備。
支持跨程序調(diào)用,Cookie 是不允許垮域訪問的,而 Token 則不存在這個問題。
三、JWT 介紹
簡介
JWT 認證流程
客戶端調(diào)用登錄接口(或者獲取 token 接口),傳入用戶名密碼。
服務(wù)端請求身份認證中心,確認用戶名密碼正確。
服務(wù)端創(chuàng)建 JWT,返回給客戶端。
客戶端拿到 JWT,進行存儲(可以存儲在緩存中,也可以存儲在數(shù)據(jù)庫中,如果是瀏覽器,可以存儲在 Cookie 中)在后續(xù)請求中,在 HTTP 請求頭中加上 JWT。
服務(wù)端校驗 JWT,校驗通過后,返回相關(guān)資源和數(shù)據(jù)。
JWT 結(jié)構(gòu)
header.payload.signature
{
"type" : "JWT",
"ALG" : "HS256"
}
標(biāo)準(zhǔn)中注冊的聲明
公共的聲明
私有的聲明
iss:JWT 簽發(fā)者
sub:JWT 所面向的用戶
aud:接收 JWT 的一方
exp:JWT 的過期時間,這個過期時間必須要大于簽發(fā)時間
nbf:定義在什么時間之前,該 JWT 都是不可用的
iat:JWT 的簽發(fā)時間
jti:JWT 的唯一身份標(biāo)識,主要用來作為一次性 token, 從而回避重放攻擊。
公共的聲明可以添加任何的信息,一般添加用戶的相關(guān)信息或其他業(yè)務(wù)需要的必要信息。但不建議添加敏感信息,因為該部分在客戶端可解密。
私有聲明是提供者和消費者所共同定義的聲明,一般不建議存放敏感信息,因為 base64 是對稱解密的,意味著該部分信息可以歸類為明文信息。
跨語言,JSON 的格式保證了跨語言的支撐
基于 Token,無狀態(tài)
占用字節(jié)小,便于傳輸
Token 存儲在 Cookie 中,這樣客戶端注銷時,自然可以清空掉
注銷時,將 Token 存放到分布式緩存中,每次校驗 Token 時區(qū)檢查下該 Token 是否已注銷。不過這樣也就失去了快速校驗 Token 的優(yōu)點。
多采用短期令牌,比如令牌有效期是 20 分鐘,這樣可以一定程度上降低注銷后 Token 可用性的風(fēng)險。
四、OAuth 2.0 介紹
簡單:不管是 OAuth 服務(wù)提供者還是應(yīng)用開發(fā)者,都很容易于理解與使用;
安全:沒有涉及到用戶密鑰等信息,更安全更靈活;
開放:任何服務(wù)提供商都可以實現(xiàn) OAuth,任何軟件開發(fā)商都可以使用 OAuth;
授權(quán)流程
客戶端:客戶端是代表資源所有者對資源服務(wù)器發(fā)出訪問受保護資源請求的應(yīng)用程序。
資源擁有者:資源擁有者是對資源具有授權(quán)能力的人。
資源服務(wù)器:資源所在的服務(wù)器。
授權(quán)服務(wù)器:為客戶端應(yīng)用程序提供不同的 Token,可以和資源服務(wù)器在統(tǒng)一服務(wù)器上,也可以獨立出去。
授權(quán)碼模式(authorization code)
授權(quán)碼模式(authorization code)是功能最完整、流程最嚴密的授權(quán)模式。它的特點就是通過客戶端的后臺服務(wù)器,與 "服務(wù)提供商" 的認證服務(wù)器進行互動。流程如下:
用戶訪問客戶端,后者將前者導(dǎo)向認證服務(wù)器。
用戶選擇是否給予客戶端授權(quán)。
假設(shè)用戶給予授權(quán),認證服務(wù)器將用戶導(dǎo)向客戶端事先指定的 "重定向 URI"(redirection URI),同時附上一個授權(quán)碼。
客戶端收到授權(quán)碼,附上早先的 "重定向 URI",向認證服務(wù)器申請令牌。這一步是在客戶端的后臺的服務(wù)器上完成的,對用戶不可見。
認證服務(wù)器核對了授權(quán)碼和重定向 URI,確認無誤后,向客戶端發(fā)送訪問令牌(access token)和更新令牌(refresh token)。
簡化模式(implicit)
簡化模式(Implicit Grant Type)不通過第三方應(yīng)用程序的服務(wù)器,直接在瀏覽器中向認證服務(wù)器申請令牌,跳過了 "授權(quán)碼" 這個步驟,因此得名。所有步驟在瀏覽器中完成,令牌對訪問者是可見的,且客戶端不需要認證。流程如下:
客戶端將用戶導(dǎo)向認證服務(wù)器。
用戶決定是否給于客戶端授權(quán)。
假設(shè)用戶給予授權(quán),認證服務(wù)器將用戶導(dǎo)向客戶端指定的 "重定向 URI",并在 URI 的 Hash 部分包含了訪問令牌。
瀏覽器向資源服務(wù)器發(fā)出請求,其中不包括上一步收到的 Hash 值。
資源服務(wù)器返回一個網(wǎng)頁,其中包含的代碼可以獲取 Hash 值中的令牌。
瀏覽器執(zhí)行上一步獲得的腳本,提取出令牌。
瀏覽器將令牌發(fā)給客戶端。
密碼模式(Resource Owner Password Credentials)
密碼模式中,用戶向客戶端提供自己的用戶名和密碼。客戶端使用這些信息,向 "服務(wù)商提供商" 索要授權(quán)。在這種模式中,用戶必須把自己的密碼給客戶端,但是客戶端不得儲存密碼。這通常用在用戶對客戶端高度信任的情況下,比如客戶端是操作系統(tǒng)的一部分,或者由一個著名公司出品。而認證服務(wù)器只有在其他授權(quán)模式無法執(zhí)行的情況下,才能考慮使用這種模式。流程如下:
用戶向客戶端提供用戶名和密碼。
客戶端將用戶名和密碼發(fā)給認證服務(wù)器,向后者請求令牌。
認證服務(wù)器確認無誤后,向客戶端提供訪問令牌。
客戶端模式(Client Credentials)
客戶端模式(Client Credentials Grant)指客戶端以自己的名義,而不是以用戶的名義,向 "服務(wù)提供商" 進行認證。嚴格地說,客戶端模式并不屬于 OAuth 框架所要解決的問題。
在這種模式中,用戶直接向客戶端注冊,客戶端以自己的名義要求 "服務(wù)提供商" 提供服務(wù),其實不存在授權(quán)問題。流程如下:
客戶端向認證服務(wù)器進行身份認證,并要求一個訪問令牌。
認證服務(wù)器確認無誤后,向客戶端提供訪問令牌。
五、思考總結(jié)
正如 David Borsos 所建議的一種方案,在微服務(wù)架構(gòu)下,我們更傾向于將 Oauth 和 JWT 結(jié)合使用,Oauth 一般用于第三方接入的場景,管理對外的權(quán)限,所以比較適合和 API 網(wǎng)關(guān)結(jié)合,針對于外部的訪問進行鑒權(quán)(當(dāng)然,底層 Token 標(biāo)準(zhǔn)采用 JWT 也是可以的)。
JWT 更加輕巧,在微服務(wù)之間進行訪問鑒權(quán)已然足夠,并且可以避免在流轉(zhuǎn)過程中和身份認證服務(wù)打交道。當(dāng)然,從能力實現(xiàn)角度來說,類似于分布式 Session 在很多場景下也是完全能滿足需求,具體怎么去選擇鑒權(quán)方案,還是要結(jié)合實際的需求來。
粉絲福利:Java從入門到入土學(xué)習(xí)路線圖
??????

??長按上方微信二維碼 2 秒
感謝點贊支持下哈 





