大家好,我是不才陳某~
今天這篇文章介紹一下Spring Cloud Gateway整合OAuth2.0實現(xiàn)認(rèn)證授權(quán)幻馁,涉及到的知識點有點多绞吁,有不清楚的可以看下陳某的往期文章哗脖。
文章目錄如下:
微服務(wù)認(rèn)證方案
微服務(wù)認(rèn)證方案目前有很多種糊肠,每個企業(yè)也是大不相同,但是總體分為兩類悯辙,如下:
網(wǎng)關(guān)只負(fù)責(zé)轉(zhuǎn)發(fā)請求琳省,認(rèn)證鑒權(quán)交給每個微服務(wù)商控制
統(tǒng)一在網(wǎng)關(guān)層面認(rèn)證鑒權(quán),微服務(wù)只負(fù)責(zé)業(yè)務(wù)
你們公司目前用的是哪種方案躲撰?
先來說說第一種方案针贬,有著很大的弊端,如下:
代碼耦合嚴(yán)重拢蛋,每個微服務(wù)都要維護一套認(rèn)證鑒權(quán)
無法做到統(tǒng)一認(rèn)證鑒權(quán)桦他,開發(fā)難度太大
第二種方案明顯是比較簡單的一種,優(yōu)點如下:
實現(xiàn)了統(tǒng)一的認(rèn)證鑒權(quán)谆棱,微服務(wù)只需要各司其職快压,專注于自身的業(yè)務(wù)
代碼耦合性低,方便后續(xù)的擴展
下面陳某就以第二種方案為例垃瞧,整合Spring Cloud Gateway+Spring Cloud Security?整合出一套統(tǒng)一認(rèn)證鑒權(quán)案例蔫劣。
案例架構(gòu)
開始擼代碼之前,先來說說大致的認(rèn)證鑒權(quán)流程个从,架構(gòu)如下圖:
大致分為四個角色脉幢,如下:
客戶端:需要訪問微服務(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ù)驗證用戶名菊值、密碼等一系列身份外驱,通過則頒發(fā)令牌給客戶端
4育灸、客戶端攜帶令牌請求資源腻窒,請求直接到了網(wǎng)關(guān)層
5昵宇、網(wǎng)關(guān)對令牌進行校驗(驗簽、過期時間校驗....)儿子、鑒權(quán)(對當(dāng)前令牌攜帶的權(quán)限)和訪問資源所需的權(quán)限進行比對瓦哎,如果權(quán)限有交集則通過校驗,直接轉(zhuǎn)發(fā)給微服務(wù)
6柔逼、微服務(wù)進行邏輯處理
針對上述架構(gòu)需要新建三個服務(wù)蒋譬,分別如下:
名稱功能
oauth2-cloud-auth-serverOAuth2.0認(rèn)證授權(quán)服
oauth2-cloud-gateway網(wǎng)關(guān)服務(wù)
oauth2-cloud-order-service訂單資源服務(wù)
案例源碼目錄如下:
認(rèn)證授權(quán)服務(wù)搭建
很多企業(yè)是將認(rèn)證授權(quán)服務(wù)直接集成到網(wǎng)關(guān)中,這么做耦合性太高了愉适,這里陳某直接將認(rèn)證授權(quán)服務(wù)抽離出來犯助。
認(rèn)證服務(wù)的搭建這里就不再細(xì)說了,上一篇文章中已經(jīng)介紹的很清楚了:OAuth2.0實戰(zhàn)维咸!使用JWT令牌認(rèn)證剂买!
新建一個oauth2-cloud-auth-server模塊,目錄如下:
和上篇文章不同的是創(chuàng)建了
JwtTokenUserDetailsService這個類癌蓖,用于從數(shù)據(jù)庫中加載用戶瞬哼,如下:
為了演示只是模擬了從數(shù)據(jù)庫中查詢,其中存了兩個用戶租副,如下:
user:具有ROLE_user權(quán)限
admin:具有ROLE_admin坐慰、ROLE_user權(quán)限
要想這個生效,還要在security的配置文件SecurityConfig中指定用僧,如下圖:
另外還整合了注冊中心Nacos结胀,詳細(xì)配置就不貼了,可以看源碼责循。有不清楚Nacos糟港,可以看之前文章:五十五張圖告訴你微服務(wù)的靈魂擺渡者Nacos究竟有多強?
案例源碼已經(jīng)上傳GitHub沼死,關(guān)注公號:碼猿技術(shù)專欄着逐,回復(fù)關(guān)鍵詞:9529?獲取意蛀!
網(wǎng)關(guān)服務(wù)搭建
網(wǎng)關(guān)使用的是Spring Cloud Gateway耸别,網(wǎng)關(guān)如何搭建這里就不再細(xì)說了,有不清楚的可以看之前文章:Spring Cloud Gateway奪命連環(huán)10問县钥?
新建一個oauth2-cloud-gateway模塊秀姐,目錄如下圖:
1、添加依賴
需要添加幾個OAuth2.0相關(guān)的依賴若贮,如下:
2省有、JWT令牌服務(wù)配置
使用JWT令牌痒留,配置要和認(rèn)證服務(wù)的令牌配置相同,代碼如下:
3蠢沿、認(rèn)證管理器自定義
新建一個JwtAuthenticationManager伸头,需要實現(xiàn)
ReactiveAuthenticationManager這個接口。
認(rèn)證管理的作用就是獲取傳遞過來的令牌舷蟀,對其進行解析恤磷、驗簽、過期時間判定野宜。
詳細(xì)代碼如下:
邏輯很簡單扫步,就是通過JWT令牌服務(wù)解析客戶端傳遞的令牌,并對其進行校驗匈子,比如上傳三處校驗失敗河胎,拋出令牌無效的異常。
拋出的異常如何處理虎敦?如何定制返回的結(jié)果游岳?
這里拋出的異常可以通過Spring Cloud Gateway的全局異常進行捕獲原茅,這個內(nèi)容在Spring Cloud Gateway奪命連環(huán)10問吭历?這篇文章有詳細(xì)的介紹。下面只貼出關(guān)鍵代碼擂橘,如下:
4晌区、鑒權(quán)管理器自定義
經(jīng)過認(rèn)證管理器JwtAuthenticationManager認(rèn)證成功后,就需要對令牌進行鑒權(quán)通贞,如果該令牌無訪問資源的權(quán)限朗若,則不允通過。
新建JwtAccessManager昌罩,實現(xiàn)
ReactiveAuthorizationManager哭懈,代碼如下:
這里的邏輯很簡單,就是取出令牌中的權(quán)限和當(dāng)前請求資源URI的權(quán)限對比茎用,如果有交集則通過遣总。
①處的代碼什么意思?
這里是直接從Redis中取出資源URI對應(yīng)的權(quán)限集合轨功,因此實際開發(fā)中需要維護資源URI和權(quán)限的對應(yīng)關(guān)系旭斥,這里不細(xì)說,為了演示古涧,陳某直接在項目啟動的時候向Redis中添加了兩個資源的權(quán)限垂券,代碼如下:
注意:實際開發(fā)中需要維護資源URI和權(quán)限的對應(yīng)關(guān)系。
②處的代碼什么意思羡滑?
這處代碼就是取出令牌中的權(quán)限集合
③處的代碼什么意思菇爪?
這處代碼就是比較兩者權(quán)限了算芯,有交集,則放行凳宙。
5熙揍、令牌無效或者過期時定制結(jié)果
在第4步,如果令牌失效或者過期近速,則會直接返回诈嘿,這里需要定制提示信息堪旧。
新建一個
RequestAuthenticationEntryPoint削葱,實現(xiàn)
ServerAuthenticationEntryPoint,代碼如下:
6淳梦、無權(quán)限時定制結(jié)果
在第4步鑒權(quán)的過程中析砸,如果無該權(quán)限,也是會直接返回爆袍,這里也需要定制提示信息首繁。
新建一個
RequestAccessDeniedHandler,實現(xiàn)ServerAccessDeniedHandler陨囊,代碼如下:
7弦疮、OAuth2.0相關(guān)配置
經(jīng)過上述6個步驟,相關(guān)組件已經(jīng)準(zhǔn)備就緒蜘醋,現(xiàn)在直接配置到OAuth2.0中胁塞。
新建SecurityConfig這個配置類,標(biāo)注注解?@EnableWebFluxSecurity压语,注意不是?@EnableWebSecurity啸罢,因為Spring Cloud Gateway是基于Flux實現(xiàn)的。詳細(xì)代碼如下:
需要配置的內(nèi)容如下:
認(rèn)證過濾器胎食,其中利用了認(rè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)中定義一個全局過濾器蜡坊,用來攔截請求,解析令牌赎败,關(guān)鍵代碼如下:
上述代碼邏輯如下:
檢查是否是白名單秕衙,白名單直接放行
檢驗令牌是否存在
解析令牌中的用戶信息
封裝用戶信息到JSON數(shù)據(jù)中
加密JSON數(shù)據(jù)
將加密后的JSON數(shù)據(jù)放入到請求頭中
好了,經(jīng)過上述8個步驟僵刮,完整的網(wǎng)關(guān)已經(jīng)搭建成功了据忘。
訂單微服務(wù)搭建
由于在網(wǎng)關(guān)層面已經(jīng)做了鑒權(quán)了(細(xì)化到每個URI),因此微服務(wù)就不用集成Spring Security單獨做權(quán)限控制了搞糕。
因此這里的微服務(wù)也是相對比較簡單了勇吊,只需要將網(wǎng)關(guān)層傳遞的加密用戶信息解密出來,放入到Request中窍仰,這樣微服務(wù)就能隨時獲取到用戶的信息了汉规。
新建一個
oauth2-cloud-order-service模塊,目錄如下:
新建一個過濾器AuthenticationFilter驹吮,用于解密網(wǎng)關(guān)傳遞的用戶數(shù)據(jù)针史,代碼如下:
新建兩個接口,返回當(dāng)前登錄的用戶信息碟狞,如下:
注意:以上兩個接口所需要的權(quán)限已經(jīng)放入到了Redis中啄枕,權(quán)限如下:
/order/login/info:ROLE_admin和ROLE_user都能訪問
/order/login/admin:ROLE_admin權(quán)限才能訪問
案例源碼已經(jīng)上傳GitHub,關(guān)注公號:碼猿技術(shù)專欄族沃,回復(fù)關(guān)鍵詞:9529?獲绕底!!
為什么要將URI和權(quán)限放入Redis竭业?
在網(wǎng)關(guān)的鑒權(quán)管理器那里是直接從Redis中獲取URI對應(yīng)的權(quán)限智润,然后和令牌中的權(quán)限比較,為什么要這樣做未辆?
這也是目前企業(yè)中比較常用的一種方式窟绷,將鑒權(quán)完全放在了網(wǎng)關(guān)層面,也實現(xiàn)了動態(tài)權(quán)限校驗咐柜。當(dāng)然有些是直接將接口的權(quán)限控制在每個微服務(wù)中兼蜈。
采用陳某的這種方案需要另外維護URI和權(quán)限的對應(yīng)關(guān)系,當(dāng)然這種難度很低拙友,便于實現(xiàn)为狸。
只是一種方案,具體是否選用還要考慮到架構(gòu)層面遗契。
測試
同時啟動上述三個服務(wù)辐棒,如下:
1、用密碼模式登錄user,獲取令牌漾根,如下:
2泰涂、使用user用戶的令牌訪問/order/login/info接口,如下:
可以看到成功返回了辐怕,因為具備ROLE_user權(quán)限逼蒙。
3、使用user用戶的令牌訪問/order/login/admin接口寄疏,如下:
可以看到直接返回了無權(quán)限訪問是牢,直接在網(wǎng)關(guān)層被攔截了。
總結(jié)
本篇文章只是簡單的整合了網(wǎng)關(guān)+OAuth2.0陕截,實際開發(fā)中還有一些細(xì)節(jié)待完善驳棱,由于文章篇幅限制,后續(xù)介紹......