javascript
实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式统一认证授权!
今天這篇文章介紹一下Spring Cloud Gateway整合OAuth2.0實現認證授權,涉及到的知識點有點多,有不清楚的可以看下陳某的往期文章。
文章目錄如下:
微服務認證方案
微服務認證方案目前有很多種,每個企業也是大不相同,但是總體分為兩類,如下:
網關只負責轉發請求,認證鑒權交給每個微服務控制
統一在網關層面認證鑒權,微服務只負責業務
你們公司目前用的哪種方案?
先來說說第一種方案,有著很大的弊端,如下:
代碼耦合嚴重,每個微服務都要維護一套認證鑒權
無法做到統一認證鑒權,開發難度太大
第二種方案明顯是比較簡單的一種,優點如下:
實現了統一的認證鑒權,微服務只需要各司其職,專注于自身的業務
代碼耦合性低,方便后續的擴展
下面陳某就以第二種方案為例,整合Spring Cloud Gateway+Spring Cloud Security 整合出一套統一認證鑒權案例。
案例架構
開始擼代碼之前,先來說說大致的認證鑒權流程,架構如下圖:
大致分為四個角色,如下:
客戶端:需要訪問微服務資源
網關:負責轉發、認證、鑒權
OAuth2.0授權服務:負責認證授權頒發令牌
微服務集合:提供資源的一系列服務。
大致流程如下:
1、客戶端發出請求給網關獲取令牌
2、網關收到請求,直接轉發給授權服務
3、授權服務驗證用戶名、密碼等一系列身份,通過則頒發令牌給客戶端
4、客戶端攜帶令牌請求資源,請求直接到了網關層
5、網關對令牌進行校驗(驗簽、過期時間校驗....)、鑒權(對當前令牌攜帶的權限)和訪問資源所需的權限進行比對,如果權限有交集則通過校驗,直接轉發給微服務
6、微服務進行邏輯處理
針對上述架構需要新建三個服務,分別如下:
案例源碼目錄如下:
認證授權服務搭建
很多企業是將認證授權服務直接集成到網關中,這么做耦合性太高了,這里陳某直接將認證授權服務抽離出來。
新建一個oauth2-cloud-auth-server模塊,目錄如下:
和上篇文章不同的是創建了JwtTokenUserDetailsService這個類,用于從數據庫中加載用戶,如下:
為了演示只是模擬了從數據庫中查詢,其中存了兩個用戶,如下:
user:具有ROLE_user權限
admin:具有ROLE_admin、ROLE_user權限
要想這個生效,還要在security的配置文件SecurityConfig中指定,如下圖:
另外還整合了注冊中心Nacos,詳細配置就不貼了,可以看源碼。
網關服務搭建
網關使用的是Spring Cloud Gateway
新建一個oauth2-cloud-gateway模塊,目錄如下圖:
1、添加依賴
需要添加幾個OAuth2.0相關的依賴,如下:
2、JWT令牌服務配置
使用JWT令牌,配置要和認證服務的令牌配置相同,代碼如下:
3、認證管理器自定義
新建一個JwtAuthenticationManager,需要實現ReactiveAuthenticationManager這個接口。
認證管理的作用就是獲取傳遞過來的令牌,對其進行解析、驗簽、過期時間判定。
詳細代碼如下:
邏輯很簡單,就是通過JWT令牌服務解析客戶端傳遞的令牌,并對其進行校驗,比如上傳三處校驗失敗,拋出令牌無效的異常。
拋出的異常如何處理?如何定制返回的結果?
這里拋出的異常可以通過Spring Cloud Gateway的全局異常進行捕獲。下面只貼出關鍵代碼,如下:
4、鑒權管理器自定義
經過認證管理器JwtAuthenticationManager認證成功后,就需要對令牌進行鑒權,如果該令牌無訪問資源的權限,則不允通過。
新建JwtAccessManager,實現ReactiveAuthorizationManager,代碼如下:
這里的邏輯很簡單,就是取出令牌中的權限和當前請求資源URI的權限對比,如果有交集則通過。
①處的代碼什么意思?
這里是直接從Redis中取出資源URI對應的權限集合,因此實際開發中需要維護資源URI和權限的對應關系,這里不細說,為了演示,陳某直接在項目啟動的時候向Redis中添加了兩個資源的權限,代碼如下:
“
注意:實際開發中需要維護資源URI和權限的對應關系。
”
②處的代碼什么意思?
這處代碼就是取出令牌中的權限集合
③處的代碼什么意思?
這處代碼就是比較兩者權限了,有交集,則放行。
5、令牌無效或者過期時定制結果
在第4步,如果令牌失效或者過期,則會直接返回,這里需要定制提示信息。
新建一個RequestAuthenticationEntryPoint,實現ServerAuthenticationEntryPoint,代碼如下:
6、無權限時定制結果
在第4步鑒權的過程中,如果無該權限,也是會直接返回,這里也需要定制提示信息。
新建一個RequestAccessDeniedHandler,實現ServerAccessDeniedHandler,代碼如下:
7、OAuth2.0相關配置
經過上述6個步驟,相關組件已經準備就緒,現在直接配置到OAuth2.0中。
新建SecurityConfig這個配置類,標注注解 @EnableWebFluxSecurity,注意不是 @EnableWebSecurity,因為Spring Cloud Gateway是基于Flux實現的。詳細代碼如下:
需要配置的內容如下:
認證過濾器,其中利用了認證管理器對令牌的校驗
鑒權管理器、令牌失效異常處理、無權限訪問異常處理
白名單配置
跨域過濾器的配置
8、全局過濾器定制
試想一下:網關層面認證鑒權成功后,下游微服務如何獲取到當前用戶的詳細信息?
陳某這里是將令牌攜帶的用戶信息解析出來,封裝成JSON數據,然后通過Base64加密,放入到請求頭中,轉發給下游微服務。
這樣一來,下游微服務只需要解密請求頭中的JSON數據,即可獲取用戶的詳細信息。
因此需要在網關中定義一個全局過濾器,用來攔截請求,解析令牌,關鍵代碼如下:
上述代碼邏輯如下:
檢查是否是白名單,白名單直接放行
檢驗令牌是否存在
解析令牌中的用戶信息
封裝用戶信息到JSON數據中
加密JSON數據
將加密后的JSON數據放入到請求頭中
好了,經過上述8個步驟,完整的網關已經搭建成功了。
訂單微服務搭建
由于在網關層面已經做了鑒權了(細化到每個URI),因此微服務就不用集成Spring Security單獨做權限控制了。
因此這里的微服務也是相對比較簡單了,只需要將網關層傳遞的加密用戶信息解密出來,放入到Request中,這樣微服務就能隨時獲取到用戶的信息了。
新建一個oauth2-cloud-order-service模塊,目錄如下:
新建一個過濾器AuthenticationFilter,用于解密網關傳遞的用戶數據,代碼如下:
新建兩個接口,返回當前登錄的用戶信息,如下:
注意:以上兩個接口所需要的權限已經放入到了Redis中,權限如下:
/order/login/info:ROLE_admin和ROLE_user都能訪問
/order/login/admin:ROLE_admin權限才能訪問
在網關的鑒權管理器那里是直接從Redis中獲取URI對應的權限,然后和令牌中的權限比較,為什么要這樣做?
這也是目前企業中比較常用的一種方式,將鑒權完全放在了網關層面,也實現了動態權限校驗。當然有些是直接將接口的權限控制在每個微服務中。
“
采用陳某的這種方案需要另外維護URI和權限的對應關系,當然這種難度很低,便于實現。
”
只是一種方案,具體是否選用還要考慮到架構層面。
測試
同時啟動上述三個服務,如下:
1、用密碼模式登錄user,獲取令牌,如下:
2、使用user用戶的令牌訪問/order/login/info接口,如下:
可以看到成功返回了,因為具備ROLE_user權限。
3、使用user用戶的令牌訪問/order/login/admin接口,如下:
可以看到直接返回了無權限訪問,直接在網關層被攔截了。
有道無術,術可成;有術無道,止于術
歡迎大家關注Java之道公眾號
好文章,我在看??
總結
以上是生活随笔為你收集整理的实战干货!Spring Cloud Gateway 整合 OAuth2.0 实现分布式统一认证授权!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 同事删库跑路后,我连表名都不能修改了?
- 下一篇: 安卓平板 python_使用安卓手机或平