開放網關統一認證服務
- 2022 年 4 月 7 日
- 筆記
- javascript, node
背景
由於DEF工程體系的歷史原因,很多工程服務並未註冊至開放網關而是私自開放介面,每個服務都維護一個client身份表,同一個client在不同開放服務間同步身份數據困難。
在使用過程中,調用方申請client流程割裂、服務認證功能後置導致每個服務提供方認證邏輯同質化、無開放介面許可權管控等功能影響服務的開放安全及client接入體感,DEF開放網關統一認證服務旨在通過流程上規範client申請鏈路,同時在client申請時指定開放服務和對應許可權介面,由網關統一認證服務實現身份認證、許可權管控,並通過Oauth2授權搭配JWT機製為接入服務提供高性能認證互信方案,消除開放服務獨立認證與授權壁壘,保證所有開放服務許可權管控自動化。
必要性
當前開放服務,如雲構建、disp、def-flow和def-work等都各自維護一套基於開放的認證和許可權體系,調用方在開放平台申請的token經網關審批後,仍需要由調用方聯繫對應開放服務負責人提供元資訊、調用許可權,由開放服務負責人手動錄入各自系統進行二級鑒權。
由於開放平台並未與開放服務進行數據打通,因此很難做到自動化,對用戶而言申請client的體感較差,對服務管理員而言需手動添加用戶元資訊,體感也很差。
在運行階段,經歷了多次認證與鑒權,特別是每個開放服務側都需實現一套簡單認證系統,每次請求都需查詢DB造成性能開銷,無法保證開放介面的性能一致性。
因此,急需解決開放服務認證體系與開放網關認證統一的問題,並且從流程上簡化客戶端接入時開放服務側的工作,最終也要保證各服務現有認證的兼容,對調用方和客戶端透明。
統一認證服務方案探究
● 兼容模式,微(開放)服務仍負責各自許可權
● OAuth2授權模式,由網關認證中心統一管理開放服務許可權
● OAuth2授權 + JWT驗證,網關認證中心授權,開放服務本地認證
探索1.兼容模式
兼容模式不改變開放服務已有的認證體系,仍然由服務自身進行認證與鑒權。但:
- 服務接入體驗差,每個開放服務需提供接入開放網關許可權體系的開放介面和補償介面(介面由於網路抖動或其他原因請求失敗,需調用補償介面保證數據與之前一致),並保證冪等
- 邏輯複雜,開放網關需維護分散式事務
- 運行時性能瓶頸,開放服務的認證每次都查表,RT大,統一治理成本高
兼容模式僅僅是對現狀的妥協並不符合我們的訴求,且引入了其他治理成本,因此放棄。
探索2.基於OAuth2的授權認證
OAuth2有幾種授權模式 — 授權碼、密碼、隱藏式和憑證式,常用的是授權碼模式,它的前提是有介面且針對用戶是人的情況;憑證模式則是針對服務的一種授權,通過提供憑證(如AK/SK)來換取token,它交互流程簡單,針對服務級別,適合內部應用使用,也契合API場景。
OAuth2的角色對應
● 客戶端:使用Client的二方服務
● 資源所有者:開放服務,如def-work
● 資源伺服器:開放服務
● 授權伺服器:開放平台
客戶端接入通過BPMS流程管控,依次由網關負責人、依賴的開放服務負責人審批,流程通過後則認為當前客戶端為可信客戶端,由業務網關認證後授權給開放服務使用。
該方案可以做到以下保證:
● 認證與許可權收斂到網關,開放服務無需自建認證體系
● 客戶端接入流程化,可信應用追溯
● 「許可權校驗模組」對開放服務透明,集成在網關插件中
● token有有效期,且可被即時撤銷,安全風險可控
但是,由於存在服務許可權校驗模組rpc調用網關Oauth2模組獲取許可權資訊,因此存在些許不足:
- 「許可權校驗模組」需RPC網關OAuth2驗證token以及許可權,性能、流量壓力較大
- 網關側OAuth2模組單點風險,若掛則所有開放介面均不可用
那麼是否有一種自簽名的token,該token簽發後可由客戶端自行驗證並獲取內部相關資訊,並且保證token使用期可控呢?這樣就替開放平台認證中心省下來流量與db等多重壓力,而且提升認證鏈路的性能,最終找到了JWT。
最終方案,基於OAuth2授權和JWT本地鑒權
JWT最大的缺點是簽發的token無法立即撤銷,需等待其超時失效。但由於我們的場景是API網關以及開放介面調用,本身是無狀態場景,網關側對每個請求都需進行一次性認證,因此token的安全失效問題便可以迎刃而解。
而優點自不必說,
● 性能優勢,開放服務本地校驗速度有保證
● 一次性認證,token用完即失效,有安全保證
使用體感
用戶在開放平台申請client時,選擇對應開放服務及重點介面時會走特殊流程審批,
對應管理員審批通過後,AK/SK即可使用
。
使用該AK/SK請求介面時,認證中心會對用戶請求進行認證與介面鑒權,認證失敗直接返回,認證通過向開放服務下發token,開放服務側接入的網關插件會本地解析token,拿到用戶資訊並存儲在請求上下文
ctx.defauth = {
clientName: ‘xxxx’,
clientCredential: ‘xxxx’,
adminId: ‘xxxx’
}
針對已有client表的開放服務,可自行upsert用戶數據至表中即可實現兼容,無需人工輸入;若服務無需存儲用戶資訊,可直接信任該認證資訊處理請求即可。