微服務鑒權設計的幾種方案
- Token透傳(不推薦)
- Fegin內部調用方式
- Dubbo內部調用方式
- Spring Boot Web + Dubbo內部調用方式
- 常規模式
- 與K8S集成
Token透傳(不推薦)
剛開始接觸微服務時網上給的方案大都數是通過透傳Token做鑒權,但我認為這種方式不是很妥當。接著往下看:
圖片
這種方式通過透傳Token使得各微服務都能獲取到當前登錄人信息,在代碼編寫上確實可能會方便,但我認為這不是一種很好的設計方式。
原因一:內部API與外部API混合在一起不太好區分。
原因二:內部調用的微服務API因該具備無狀態性質,這樣才能保證方法的原子性以提高代碼復用率。
換句話說:B服務提供API時不因該關心當前是否為登錄狀態,登錄狀態應該由路由中的第一個服務校驗維護,在調用后續服務時應該顯示的傳入相關參數。比如以下場景:
場景一:用戶簽到添加積分
場景二:后臺管理員給用戶手動添加積分
場景三:分布式調度批量增加用戶積分
根據需求積分服務提供了一個給用戶添加積分的API,如果你的API是通過獲取的當前登錄用戶ID增加的積分,那么面對場景二時你需要重新編寫一個給用戶添加積分的API,因為當前登錄的是后臺管理員而不是用戶(代碼復用率較低)
不透傳數據,顯示的提供入參
圖片
路由到達的第一個服務已經對Token進行了解析認證并將userId顯示的傳遞給了后續服務,后續服務不需要再對token進行解析認證。根據1.1的三個場景只需要提供一個入參包含userId的API,保證了函數的原子性提供代碼復用率。
注意: 提供的API不能暴露給外網,我們需要在路徑上做區分,避免外網非法訪問內部API。我們可以訂好內部調用API路徑規則,如:/api/inside/\** 。在網關層拒絕內部調用API請求的訪問。
統一授權
統一授權是指:將API鑒權集中在應用網關上
Fegin內部調用方式
Spring Cloud Gateway + Fegin內部調用,集中在Gateway上做統一認證鑒權,鑒權后在請求頭中添加鑒權后的信息轉發給后續服務,如:userId等。。。
圖片
缺點:A服務調用B服務時,B服務需要寫一個內部調用的Controller接口A服務才能通過Fegin調用到B服務,增加了代碼量(這里的設計方案是內部調用與外部調用Controller是分開的)
Dubbo內部調用方式
Spring Cloud Gateway + Dubbo內部調用,集中在Gateway上做統一認證鑒權,鑒權后在請求頭中添加鑒權后的信息轉發給后續服務,如:userId等。。。
優點:與第一種相比不需要額外編寫一個Controller接口,只有本地service與遠程DubboService的區別,代碼更簡潔。
缺點:項目技術棧略微增加了復雜度。
Spring Boot Web + Dubbo內部調用方式
這里的設計方案直接去掉了Gateway,直接使用了一個Spring Boot Web項目來代替Gateway。但需要注意的是應該將Web項目的容器換成Undertow,因為Tomcat是阻塞式的容器,不換也不是不行,但吞吐量可能會少一下,Undertow是非阻塞式的容器,可以與Gateway到達相同的效果。(非阻塞式:當請求為線程進入阻塞狀態時,當前線程會被掛起,當前的計算資源會去做別的事情,當被掛起的線程收到響應時才會被繼續執行,壓榨CPU用更少的資源做更多的事情,但并不會提升性能)
因為去掉了Gateway我們需要將所有服務的Controller集成到Web應用,然后在這個Web應用上做統一認證授權。如果將所有代碼寫到Web應用中,這樣可能不合適,我們可以選擇每個服務創建一個Controller模塊,Web網關服務只有一個啟動類,通過依賴的方式集成所有服務的Controller。
優點:簡化了項目結構,所有服務只有service代碼。性能壓測時不用考慮Gateway的線程池使用情況,業務服務只需要考慮Dubbo線程池的使用情況。
缺點:沒辦法通過配置中心動態調整路由。比如說增加了一個服務Gateway可以不重啟通過配置中心增加路由配置即可。
非統一授權
非統一授權:不在應用網關上集成鑒權,網關只有單一的路由轉發業務。各位服務都有自己的鑒權方式,當然也可以通過jar包的方式統一各服務的鑒權方式。
常規模式
通過編寫通用的鑒權模塊,各服務集成該模塊。該模塊具備以下功能:
- JWT Token解析
- 權限校驗攔截
- 緩存(本地緩存\Redis緩存)
這種模式更適合大型項目團隊,可能各微服務都由一個項目組負責。各服務維護自己的權限規則(這里指的是權限規則數據,規則是統一的)
圖片
該模式下由于應用網關比較輕量級,不再涉及復雜的鑒權流程,使得項目部署可以更靈活,當我們使用K8S部署項目時,我們可以將應用網關替換成K8S中的Ingress網關。
我們先看常規模式部署在K8S中完整的鏈路:
圖片
當用戶訪問時會先到達K8S Ingress網關通過應用網關Service的負載均衡調用應用網關,應用網關需要通過注冊中心獲取服務注冊列表,通過服務注冊列表負載均衡到后續服務。
與K8S集成
我們再來看看將應用網關替換成K8S中的Ingress網關的完整鏈路:
圖片
這里不僅只是去掉了應用網關,同時我們通過K8S Service 負載均衡的能力去掉了注冊中心。減少了我們部署微服務時還要額外搭建一套注冊中心。同時減少了一層沒必要的轉發。至于K8S中的Service,大家可以理解成一個本地的host假域名,比如我們在K8S給商品創建一個Service,名稱為:goods-svc。那么我們可以通過goods-svc直連。如:
- http://goods-svc:8080/api/goods/info/10001
- dubbo://goods-svc:20880
方案沒有對錯,選擇適合自己的就是最好的。
相關鏈接:juejin.cn/post/7329352197837029385