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