引言: 本文系《認(rèn)證鑒權(quán)與API權(quán)限控制在微服務(wù)架構(gòu)中的設(shè)計(jì)與實(shí)現(xiàn)》系列的第三篇,,本文重點(diǎn)講解token以及API級(jí)別的鑒權(quán)。本文對(duì)涉及到的大部分代碼進(jìn)行了分析,,歡迎訂閱本系列文章,。
在開始講解這一篇文章之前,,先對(duì)之前兩篇文章進(jìn)行回憶下。在第一篇《認(rèn)證鑒權(quán)與API權(quán)限控制在微服務(wù)架構(gòu)中的設(shè)計(jì)與實(shí)現(xiàn)(一)》介紹了該項(xiàng)目的背景以及技術(shù)調(diào)研與最后選型,。第二篇《認(rèn)證鑒權(quán)與API權(quán)限控制在微服務(wù)架構(gòu)中的設(shè)計(jì)與實(shí)現(xiàn)(二)》畫出了簡(jiǎn)要的登錄和校驗(yàn)的流程圖,,并重點(diǎn)講解了用戶身份的認(rèn)證與token發(fā)放的具體實(shí)現(xiàn)。
本文重點(diǎn)講解鑒權(quán),,包括兩個(gè)方面:token合法性以及API級(jí)別的操作權(quán)限,。首先token合法性很容易理解,第二篇文章講解了獲取授權(quán)token的一系列流程,,token是否是認(rèn)證服務(wù)器頒發(fā)的,,必然是需要驗(yàn)證的。其次對(duì)于API級(jí)別的操作權(quán)限,,將上下文信息不具備操作權(quán)限的請(qǐng)求直接拒絕,,當(dāng)然此處是設(shè)計(jì)token合法性校驗(yàn)在先,其次再對(duì)操作權(quán)限進(jìn)行驗(yàn)證,,如果前一個(gè)驗(yàn)證直接拒絕,,通過則進(jìn)入操作權(quán)限驗(yàn)證。
ResourceServer配置在第一篇就列出了,,在進(jìn)入鑒權(quán)之前,,把這邊的配置搞清,即使有些配置在本項(xiàng)目中沒有用到,,大家在自己的項(xiàng)目有可能用到,。
@EnableResourceServer這個(gè)注解很重要,,OAuth2資源服務(wù)器的簡(jiǎn)便注解,。其使得Spring Security filter通過請(qǐng)求中的OAuth2 token來驗(yàn)證請(qǐng)求。通常與EnableWebSecurity配合使用,,該注解還創(chuàng)建了硬編碼的@Order(3) WebSecurityConfigurerAdapter,由于當(dāng)前spring的技術(shù),,order的順序不易修改,,所以在項(xiàng)目中避免還有其他order=3的配置。
關(guān)聯(lián)的HttpSecurity,,與之前的 Spring Security XML中的 "http"元素配置類似,,它允許配置基于web安全以針對(duì)特定http請(qǐng)求。默認(rèn)是應(yīng)用到所有的請(qǐng)求,,通過requestMatcher可以限定具體URL范圍,。HttpSecurity類圖如下。
總的來說:HttpSecurity是SecurityBuilder接口的一個(gè)實(shí)現(xiàn)類,,從名字上我們就可以看出這是一個(gè)HTTP安全相關(guān)的構(gòu)建器,。當(dāng)然我們?cè)跇?gòu)建的時(shí)候可能需要一些配置,,當(dāng)我們調(diào)用HttpSecurity對(duì)象的方法時(shí),實(shí)際上就是在進(jìn)行配置,。
authorizeRequests(),,formLogin()、httpBasic()這三個(gè)方法返回的分別是ExpressionUrlAuthorizationConfigurer,、FormLoginConfigurer,、HttpBasicConfigurer,他們都是SecurityConfigurer接口的實(shí)現(xiàn)類,,分別代表的是不同類型的安全配置器,。
因此,從總的流程上來說,,當(dāng)我們?cè)谶M(jìn)行配置的時(shí)候,,需要一個(gè)安全構(gòu)建器SecurityBuilder(例如我們這里的HttpSecurity),SecurityBuilder實(shí)例的創(chuàng)建需要有若干安全配置器SecurityConfigurer實(shí)例的配合,。
關(guān)聯(lián)的ResourceServerSecurityConfigurer,,為資源服務(wù)器添加特殊的配置,默認(rèn)的適用于很多應(yīng)用,,但是這邊的修改至少以resourceId為單位,。類圖如下。
ResourceServerSecurityConfigurer創(chuàng)建了OAuth2核心過濾器OAuth2AuthenticationProcessingFilter,,并為其提供固定了OAuth2AuthenticationManager,。只有被OAuth2AuthenticationProcessingFilter攔截到的oauth2相關(guān)請(qǐng)求才被特殊的身份認(rèn)證器處理。同時(shí)設(shè)置了TokenExtractor,、異常處理實(shí)現(xiàn),。
OAuth2AuthenticationProcessingFilter是OAuth2保護(hù)資源的預(yù)先認(rèn)證過濾器。配合OAuth2AuthenticationManager使用,,根據(jù)請(qǐng)求獲取到OAuth2 token,,之后就會(huì)使用OAuth2Authentication來填充Spring Security上下文。
OAuth2AuthenticationManager在前面的文章給出的AuthenticationManager類圖就出現(xiàn)了,,與token認(rèn)證相關(guān),。這邊略過貼出源碼進(jìn)行講解,讀者可以自行閱讀,。
鑒權(quán)主要是使用內(nèi)置的endpoint /oauth/check_token,,筆者將對(duì)端點(diǎn)的分析放在前面,因?yàn)檫@是鑒權(quán)的唯一入口,。下面我們來看下該API接口中的主要代碼,。
看過security-oauth源碼的同學(xué)可能立馬就看出上述代碼與源碼不同,熟悉/oauth/check_token校驗(yàn)流程的也會(huì)看出來,,這邊筆者對(duì)security-oauth jar進(jìn)行了重新編譯,,修改了部分源碼用于該項(xiàng)目需求的場(chǎng)景。主要是加入了前置的API級(jí)別的權(quán)限校驗(yàn),。
從上面的CheckTokenEndpoint中可以看出,,對(duì)于token合法性驗(yàn)證首先是識(shí)別請(qǐng)求體中的token。用到的主要方法是ResourceServerTokenServices提供的readAccessToken()方法,。該接口的實(shí)現(xiàn)類為DefaultTokenServices,,在之前的配置中有講過這邊配置了jdbc的TokenStore。
readAccessToken()檢索出該token值的完整信息,。上述代碼比較簡(jiǎn)單,涉及到的邏輯也不復(fù)雜,,此處簡(jiǎn)單講解,。下圖為debug token校驗(yàn)的變量信息,讀者可以自己動(dòng)手操作下,,截圖僅供參考,。
至于后面的步驟,loadAuthentication()為特定的access token 加載credentials,。得到的credentials 與token作為convertAccessToken()參數(shù),,得到校驗(yàn)token的response。
筆者項(xiàng)目目前都是基于Web的權(quán)限驗(yàn)證,,之前遺留的一個(gè)巨大的單體應(yīng)用系統(tǒng)正在逐漸拆分,,然而當(dāng)前又不能完全拆分完善。為了同時(shí)兼容新舊服務(wù),,盡量減少對(duì)業(yè)務(wù)系統(tǒng)的入侵,,實(shí)現(xiàn)微服務(wù)的統(tǒng)一性和獨(dú)立性。筆者根據(jù)業(yè)務(wù)業(yè)務(wù)場(chǎng)景,,嘗試在Auth處做操作權(quán)限校驗(yàn),。
首先想到的是資源服務(wù)器配置ResourceServer,如:
這樣做需要將每個(gè)操作接口的API權(quán)限控制放在各個(gè)不同的業(yè)務(wù)服務(wù),,每個(gè)服務(wù)在接收到請(qǐng)求后,,需要先從Auth服務(wù)取出該token 對(duì)應(yīng)的role和scope等權(quán)限信息。這個(gè)方法肯定是可行的,,但是由于項(xiàng)目鑒權(quán)的粒度更細(xì),而且暫時(shí)不想大動(dòng)原有系統(tǒng),,在加上之前網(wǎng)關(guān)設(shè)計(jì),,網(wǎng)關(guān)調(diào)用Auth服務(wù)校驗(yàn)token合法性,所以最后決定在Auth系統(tǒng)調(diào)用中,把這些校驗(yàn)一起解決完,。
文章開頭資源服務(wù)器的配置代碼可以看出,,對(duì)于所有的資源并沒有做攔截,因?yàn)榫W(wǎng)關(guān)處是調(diào)用Auth系統(tǒng)的相關(guān)endpoint,,并不是所有的請(qǐng)求url都會(huì)經(jīng)過一遍Auth系統(tǒng),,所以對(duì)于所有的資源,在Auth系統(tǒng)中,,定義需要鑒權(quán)接口所需要的API權(quán)限,,然后根據(jù)上下文進(jìn)行匹配。這是采用的第二種方式,,也是筆者目前采用的方法,。當(dāng)然這種方式的弊端也很明顯,一旦并發(fā)量大,,網(wǎng)關(guān)還要耗時(shí)在調(diào)用Auth系統(tǒng)的鑒權(quán)上,,TPS勢(shì)必要下降很多,對(duì)于一些不需要鑒權(quán)的服務(wù)接口也會(huì)引起不可用,。另外一點(diǎn)是,,對(duì)于某些特殊權(quán)限的接口,需要的上下文信息很多,,可能并不能完全覆蓋,,對(duì)于此,筆者的解決是分兩方面:一是盡量將這些特殊情況進(jìn)行分類,,某一類的情況統(tǒng)一解決,;二是將嚴(yán)苛的校驗(yàn)降低,對(duì)于上下文校驗(yàn)失敗的直接拒絕,,而通過的,,對(duì)于某些接口,在接口內(nèi)進(jìn)行操作之前,,對(duì)特殊的地方還要再次進(jìn)行校驗(yàn),。
上面在講endpoint有提到這邊對(duì)源碼進(jìn)行了改寫。CheckTokenEntity是自定義的DTO,,這這個(gè)類中定義了鑒權(quán)需要的上下文,,這里是指能校驗(yàn)操作權(quán)限的最小集合,如URI,、roleId,、affairId等等。另外定義了CheckPermissions接口,,其方法checkPermission(CheckTokenEntity checkTokenEntity)返回了check的結(jié)果,。而其具體實(shí)現(xiàn)類則定義在Auth系統(tǒng)中。筆者項(xiàng)目中調(diào)用的實(shí)例如下:
關(guān)于jar包spring-cloud-starter-oauth2中的具體修改內(nèi)容,大家可以看下文末筆者的GitHub項(xiàng)目,。通過自定義CustomCheckPermission,,覆寫checkPermission()方法,大家也可以對(duì)自己業(yè)務(wù)的操作權(quán)限進(jìn)行校驗(yàn),,非常靈活,。這邊涉及到具體業(yè)務(wù),筆者在項(xiàng)目中只提供接口,,具體的實(shí)現(xiàn)需要讀者自行完成,。
本文的源碼地址:
參考
原文鏈接:http:///2017/10/24/security3/ 本次培訓(xùn)內(nèi)容包含:Kubernetes架構(gòu)、Kubernetes安裝,、Kubernetes功能導(dǎo)覽,、監(jiān)控解決方案、Kubernetes高階——設(shè)計(jì)和實(shí)現(xiàn),、Kubernetes落地實(shí)踐等,,點(diǎn)擊識(shí)別下方二維碼加微信好友了解具體培訓(xùn)內(nèi)容。
|
|