Spring OAuth2.0 提供者實(shí)現(xiàn)原理:
Spring OAuth2.0提供者實(shí)際上分為:
授權(quán)服務(wù) Authorization Service.
資源服務(wù) Resource Service.
雖然這兩個(gè)提供者有時(shí)候可能存在同一個(gè)應(yīng)用程序中鳖链,但在Spring Security OAuth中你可以把
他它們各自放在不同的應(yīng)用上,而且你可以有多個(gè)資源服務(wù)畦粮,它們共享同一個(gè)中央授權(quán)服
務(wù)硬爆。
所有獲取令牌的請(qǐng)求都將會(huì)在Spring MVC controller endpoints中進(jìn)行處理沦泌,并且訪問(wèn)受保護(hù)
的資源服務(wù)的處理流程將會(huì)放在標(biāo)準(zhǔn)的Spring Security請(qǐng)求過(guò)濾器中(filters)烙常。
下面是配置一個(gè)授權(quán)服務(wù)必須要實(shí)現(xiàn)的endpoints:
AuthorizationEndpoint:用來(lái)作為請(qǐng)求者獲得授權(quán)的服務(wù)荆永,默認(rèn)的URL是/oauth/authorize.
TokenEndpoint:用來(lái)作為請(qǐng)求者獲得令牌(Token)的服務(wù),默認(rèn)的URL是/oauth/token.
下面是配置一個(gè)資源服務(wù)必須要實(shí)現(xiàn)的過(guò)濾器:
OAuth2AuthenticationProcessingFilter:用來(lái)作為認(rèn)證令牌(Token)的一個(gè)處理流程過(guò)濾器般渡。只有當(dāng)過(guò)濾器通過(guò)之后,請(qǐng)求者才能獲得受保護(hù)的資源芙盘。
配置提供者(授權(quán)驯用、資源)都可以通過(guò)簡(jiǎn)單的Java注解@Configuration來(lái)進(jìn)行適配,你也可以使用基于XML的聲明式語(yǔ)法來(lái)進(jìn)行配置儒老,如果你打算這樣做的話蝴乔,那么請(qǐng)使用http://www.springframework.org/schema/security/spring-security-oauth2.xsd來(lái)作為XML的schema(即XML概要定義)以及使用http://www.springframework.org/schema/security/oauth2來(lái)作為命名空間。
一驮樊、授權(quán)服務(wù)配置:
配置一個(gè)授權(quán)服務(wù)薇正,你需要考慮幾種授權(quán)類型(Grant Type),不同的授權(quán)類型為客戶端(Client)提供了不同的獲取令牌(Token)方式囚衔,為了實(shí)現(xiàn)并確定這幾種授權(quán)挖腰,需要配置使用 ClientDetailsService 和 TokenService 來(lái)開啟或者禁用這幾種授權(quán)機(jī)制。到這里就請(qǐng)注意了练湿,不管你使用什么樣的授權(quán)類型(Grant Type)猴仑,每一個(gè)客戶端(Client)都能夠通過(guò)明確的配置以及權(quán)限來(lái)實(shí)現(xiàn)不同的授權(quán)訪問(wèn)機(jī)制。這也就是說(shuō)肥哎,假如你提供了一個(gè)支持"client_credentials"的授權(quán)方式辽俗,并不意味著客戶端就需要使用這種方式來(lái)獲得授權(quán)。下面是幾種授權(quán)類型的列表篡诽,具體授權(quán)機(jī)制的含義可以參見RFC6749(中文版本):
authorization_code:授權(quán)碼類型崖飘。
implicit:隱式授權(quán)類型。
password:資源所有者(即用戶)密碼類型杈女。
client_credentials:客戶端憑據(jù)(客戶端ID以及Key)類型朱浴。
refresh_token:通過(guò)以上授權(quán)獲得的刷新令牌來(lái)獲取新的令牌。
可以用 @EnableAuthorizationServer 注解來(lái)配置OAuth2.0 授權(quán)服務(wù)機(jī)制碧信,通過(guò)使用@Bean注解的幾個(gè)方法一起來(lái)配置這個(gè)授權(quán)服務(wù)赊琳。下面咱們介紹幾個(gè)配置類,這幾個(gè)配置是由Spring創(chuàng)建的獨(dú)立的配置對(duì)象砰碴,它們會(huì)被Spring傳入AuthorizationServerConfigurer中:
ClientDetailsServiceConfigurer:用來(lái)配置客戶端詳情服務(wù)(ClientDetailsService)躏筏,客戶端詳情信息在這里進(jìn)行初始化,你能夠把客戶端詳情信息寫死在這里或者是通過(guò)數(shù)據(jù)庫(kù)來(lái)存儲(chǔ)調(diào)取詳情信息呈枉。
AuthorizationServerSecurityConfigurer:用來(lái)配置令牌端點(diǎn)(Token Endpoint)的安全約束.
AuthorizationServerEndpointsConfigurer:用來(lái)配置授權(quán)(authorization)以及令牌(token)的訪問(wèn)端點(diǎn)和令牌服務(wù)(token services)趁尼。
(譯者注:以上的配置可以選擇繼承AuthorizationServerConfigurerAdapter并且覆寫其中的三個(gè)configure方法來(lái)進(jìn)行配置埃碱。)
配置授權(quán)服務(wù)一個(gè)比較重要的方面就是提供一個(gè)授權(quán)碼給一個(gè)OAuth客戶端(通過(guò) authorization_code 授權(quán)類型),一個(gè)授權(quán)碼的獲取是OAuth客戶端跳轉(zhuǎn)到一個(gè)授權(quán)頁(yè)面酥泞,然后通過(guò)驗(yàn)證授權(quán)之后服務(wù)器重定向到OAuth客戶端砚殿,并且在重定向連接中附帶返回一個(gè)授權(quán)碼。
如果你是通過(guò)XML來(lái)進(jìn)行配置的話芝囤,那么可以使用 <authorization-server/> 標(biāo)簽來(lái)進(jìn)行配置似炎。
(譯者注:想想現(xiàn)在國(guó)內(nèi)各大平臺(tái)的社會(huì)化登陸服務(wù),例如騰訊悯姊,用戶要使用QQ登錄到某個(gè)網(wǎng)站羡藐,這個(gè)網(wǎng)站是跳轉(zhuǎn)到了騰訊的登陸授權(quán)頁(yè)面,然后用戶登錄并且確定授權(quán)之后跳轉(zhuǎn)回目標(biāo)網(wǎng)站悯许,這種授權(quán)方式規(guī)范在我上面提供的鏈接*RFC6749*的第4.1節(jié)有詳細(xì)闡述仆嗦。)
配置客戶端詳情信息(Client Details):
ClientDetailsServiceConfigurer (AuthorizationServerConfigurer 的一個(gè)回調(diào)配置項(xiàng),見上的概述) 能夠使用內(nèi)存或者JDBC來(lái)實(shí)現(xiàn)客戶端詳情服務(wù)(ClientDetailsService)先壕,有幾個(gè)重要的屬性如下列表:
clientId:(必須的)用來(lái)標(biāo)識(shí)客戶的Id瘩扼。
secret:(需要值得信任的客戶端)客戶端安全碼,如果有的話垃僚。
scope:用來(lái)限制客戶端的訪問(wèn)范圍集绰,如果為空(默認(rèn))的話,那么客戶端擁有全部的訪問(wèn)范圍冈在。
authorizedGrantTypes:此客戶端可以使用的授權(quán)類型倒慧,默認(rèn)為空。
authorities:此客戶端可以使用的權(quán)限(基于Spring Security authorities)包券。
客戶端詳情(Client Details)能夠在應(yīng)用程序運(yùn)行的時(shí)候進(jìn)行更新纫谅,可以通過(guò)訪問(wèn)底層的存儲(chǔ)服務(wù)(例如將客戶端詳情存儲(chǔ)在一個(gè)關(guān)系數(shù)據(jù)庫(kù)的表中,就可以使用 JdbcClientDetailsService)或者通過(guò) ClientDetailsManager 接口(同時(shí)你也可以實(shí)現(xiàn) ClientDetailsService 接口)來(lái)進(jìn)行管理溅固。
(譯者注:不過(guò)我并沒有找到 ClientDetailsManager 這個(gè)接口文件付秕,只找到了 ClientDetailsService)
管理令牌(Managing Token):
AuthorizationServerTokenServices 接口定義了一些操作使得你可以對(duì)令牌進(jìn)行一些必要的管理,在使用這些操作的時(shí)候請(qǐng)注意以下幾點(diǎn):
當(dāng)一個(gè)令牌被創(chuàng)建了侍郭,你必須對(duì)其進(jìn)行保存询吴,這樣當(dāng)一個(gè)客戶端使用這個(gè)令牌對(duì)資源服務(wù)進(jìn)行請(qǐng)求的時(shí)候才能夠引用這個(gè)令牌。
當(dāng)一個(gè)令牌是有效的時(shí)候亮元,它可以被用來(lái)加載身份信息猛计,里面包含了這個(gè)令牌的相關(guān)權(quán)限。
當(dāng)你自己創(chuàng)建 AuthorizationServerTokenServices 這個(gè)接口的實(shí)現(xiàn)時(shí)爆捞,你可能需要考慮一下使用 DefaultTokenServices 這個(gè)類奉瘤,里面包含了一些有用實(shí)現(xiàn),你可以使用它來(lái)修改令牌的格式和令牌的存儲(chǔ)煮甥。默認(rèn)的盗温,當(dāng)它嘗試創(chuàng)建一個(gè)令牌的時(shí)候藕赞,是使用隨機(jī)值來(lái)進(jìn)行填充的,除了持久化令牌是委托一個(gè) TokenStore 接口來(lái)實(shí)現(xiàn)以外卖局,這個(gè)類幾乎幫你做了所有的事情斧蜕。并且 TokenStore 這個(gè)接口有一個(gè)默認(rèn)的實(shí)現(xiàn),它就是 InMemoryTokenStore 砚偶,如其命名批销,所有的令牌是被保存在了內(nèi)存中。除了使用這個(gè)類以外蟹演,你還可以使用一些其他的預(yù)定義實(shí)現(xiàn)风钻,下面有幾個(gè)版本,它們都實(shí)現(xiàn)了TokenStore接口:
InMemoryTokenStore:這個(gè)版本的實(shí)現(xiàn)是被默認(rèn)采用的酒请,它可以完美的工作在單服務(wù)器上(即訪問(wèn)并發(fā)量壓力不大的情況下,并且它在失敗的時(shí)候不會(huì)進(jìn)行備份)鸣个,大多數(shù)的項(xiàng)目都可以使用這個(gè)版本的實(shí)現(xiàn)來(lái)進(jìn)行嘗試羞反,你可以在開發(fā)的時(shí)候使用它來(lái)進(jìn)行管理,因?yàn)椴粫?huì)被保存到磁盤中囤萤,所以更易于調(diào)試昼窗。
JdbcTokenStore:這是一個(gè)基于JDBC的實(shí)現(xiàn)版本,令牌會(huì)被保存進(jìn)關(guān)系型數(shù)據(jù)庫(kù)涛舍。使用這個(gè)版本的實(shí)現(xiàn)時(shí)澄惊,你可以在不同的服務(wù)器之間共享令牌信息,使用這個(gè)版本的時(shí)候請(qǐng)注意把"spring-jdbc"這個(gè)依賴加入到你的classpath當(dāng)中富雅。
JwtTokenStore:這個(gè)版本的全稱是 JSON Web Token(JWT)掸驱,它可以把令牌相關(guān)的數(shù)據(jù)進(jìn)行編碼(因此對(duì)于后端服務(wù)來(lái)說(shuō),它不需要進(jìn)行存儲(chǔ)没佑,這將是一個(gè)重大優(yōu)勢(shì))毕贼,但是它有一個(gè)缺點(diǎn),那就是撤銷一個(gè)已經(jīng)授權(quán)令牌將會(huì)非常困難蛤奢,所以它通常用來(lái)處理一個(gè)生命周期較短的令牌以及撤銷刷新令牌(refresh_token)鬼癣。另外一個(gè)缺點(diǎn)就是這個(gè)令牌占用的空間會(huì)比較大,如果你加入了比較多用戶憑證信息啤贩。JwtTokenStore 不會(huì)保存任何數(shù)據(jù)待秃,但是它在轉(zhuǎn)換令牌值以及授權(quán)信息方面與 DefaultTokenServices 所扮演的角色是一樣的。
JWT令牌(JWT Tokens):
使用JWT令牌你需要在授權(quán)服務(wù)中使用 JwtTokenStore痹屹,資源服務(wù)器也需要一個(gè)解碼的Token令牌的類 JwtAccessTokenConverter章郁,JwtTokenStore依賴這個(gè)類來(lái)進(jìn)行編碼以及解碼,因此你的授權(quán)服務(wù)以及資源服務(wù)都需要使用這個(gè)轉(zhuǎn)換類痢掠。Token令牌默認(rèn)是有簽名的驱犹,并且資源服務(wù)需要驗(yàn)證這個(gè)簽名嘲恍,因此呢,你需要使用一個(gè)對(duì)稱的Key值雄驹,用來(lái)參與簽名計(jì)算佃牛,這個(gè)Key值存在于授權(quán)服務(wù)以及資源服務(wù)之中∫接撸或者你可以使用非對(duì)稱加密算法來(lái)對(duì)Token進(jìn)行簽名俘侠,Public Key公布在/oauth/token_key這個(gè)URL連接中,默認(rèn)的訪問(wèn)安全規(guī)則是"denyAll()"蔬将,即在默認(rèn)的情況下它是關(guān)閉的爷速,你可以注入一個(gè)標(biāo)準(zhǔn)的 SpEL 表達(dá)式到 AuthorizationServerSecurityConfigurer 這個(gè)配置中來(lái)將它開啟(例如使用"permitAll()"來(lái)開啟可能比較合適,因?yàn)樗且粋€(gè)公共密鑰)霞怀。
如果你要使用 JwtTokenStore惫东,請(qǐng)務(wù)必把"spring-security-jwt"這個(gè)依賴加入到你的classpath中。
配置授權(quán)類型(Grant Types):
授權(quán)是使用 AuthorizationEndpoint 這個(gè)端點(diǎn)來(lái)進(jìn)行控制的毙石,你能夠使用 AuthorizationServerEndpointsConfigurer 這個(gè)對(duì)象的實(shí)例來(lái)進(jìn)行配置(AuthorizationServerConfigurer 的一個(gè)回調(diào)配置項(xiàng)廉沮,見上的概述) ,如果你不進(jìn)行設(shè)置的話徐矩,默認(rèn)是除了資源所有者密碼(password)授權(quán)類型以外滞时,支持其余所有標(biāo)準(zhǔn)授權(quán)類型的(RFC6749),我們來(lái)看一下這個(gè)配置對(duì)象有哪些屬性可以設(shè)置吧滤灯,如下列表:
authenticationManager:認(rèn)證管理器坪稽,當(dāng)你選擇了資源所有者密碼(password)授權(quán)類型的時(shí)候,請(qǐng)?jiān)O(shè)置這個(gè)屬性注入一個(gè) AuthenticationManager 對(duì)象鳞骤。
userDetailsService:如果啊窒百,你設(shè)置了這個(gè)屬性的話,那說(shuō)明你有一個(gè)自己的 UserDetailsService 接口的實(shí)現(xiàn)弟孟,或者你可以把這個(gè)東西設(shè)置到全局域上面去(例如 GlobalAuthenticationManagerConfigurer 這個(gè)配置對(duì)象)贝咙,當(dāng)你設(shè)置了這個(gè)之后,那么 "refresh_token" 即刷新令牌授權(quán)類型模式的流程中就會(huì)包含一個(gè)檢查拂募,用來(lái)確保這個(gè)賬號(hào)是否仍然有效庭猩,假如說(shuō)你禁用了這個(gè)賬戶的話。
authorizationCodeServices:這個(gè)屬性是用來(lái)設(shè)置授權(quán)碼服務(wù)的(即 AuthorizationCodeServices 的實(shí)例對(duì)象)陈症,主要用于 "authorization_code" 授權(quán)碼類型模式蔼水。
implicitGrantService:這個(gè)屬性用于設(shè)置隱式授權(quán)模式,用來(lái)管理隱式授權(quán)模式的狀態(tài)录肯。
tokenGranter:這個(gè)屬性就很牛B了趴腋,當(dāng)你設(shè)置了這個(gè)東西(即 TokenGranter 接口實(shí)現(xiàn)),那么授權(quán)將會(huì)交由你來(lái)完全掌控,并且會(huì)忽略掉上面的這幾個(gè)屬性优炬,這個(gè)屬性一般是用作拓展用途的颁井,即標(biāo)準(zhǔn)的四種授權(quán)模式已經(jīng)滿足不了你的需求的時(shí)候,才會(huì)考慮使用這個(gè)蠢护。
在XML配置中呢雅宾,你可以使用 "authorization-server" 這個(gè)標(biāo)簽元素來(lái)進(jìn)行設(shè)置。
配置授權(quán)端點(diǎn)的URL(Endpoint URLs):
AuthorizationServerEndpointsConfigurer 這個(gè)配置對(duì)象(AuthorizationServerConfigurer 的一個(gè)回調(diào)配置項(xiàng)葵硕,見上的概述) 有一個(gè)叫做 pathMapping() 的方法用來(lái)配置端點(diǎn)URL鏈接眉抬,它有兩個(gè)參數(shù):
第一個(gè)參數(shù):String 類型的,這個(gè)端點(diǎn)URL的默認(rèn)鏈接懈凹。
第二個(gè)參數(shù):String 類型的蜀变,你要進(jìn)行替代的URL鏈接。
以上的參數(shù)都將以 "/" 字符為開始的字符串介评,框架的默認(rèn)URL鏈接如下列表库北,可以作為這個(gè) pathMapping() 方法的第一個(gè)參數(shù):
/oauth/authorize:授權(quán)端點(diǎn)。
/oauth/token:令牌端點(diǎn)们陆。
/oauth/confirm_access:用戶確認(rèn)授權(quán)提交端點(diǎn)贤惯。
/oauth/error:授權(quán)服務(wù)錯(cuò)誤信息端點(diǎn)。
/oauth/check_token:用于資源服務(wù)訪問(wèn)的令牌解析端點(diǎn)棒掠。
/oauth/token_key:提供公有密匙的端點(diǎn),如果你使用JWT令牌的話屁商。
需要注意的是授權(quán)端點(diǎn)這個(gè)URL應(yīng)該被Spring Security保護(hù)起來(lái)只供授權(quán)用戶訪問(wèn)烟很,我們來(lái)看看在標(biāo)準(zhǔn)的Spring Security中 WebSecurityConfigurer 是怎么用的。
@Overrideprotectedvoidconfigure(HttpSecurity http)throws Exception {
? ? http .authorizeRequests().antMatchers("/login").permitAll().and()
? ? // default protection for all resources (including /oauth/authorize).authorizeRequests() .anyRequest().hasRole("USER")
? ? // ... more configuration, e.g. for form login}
注意:如果你的應(yīng)用程序中既包含授權(quán)服務(wù)又包含資源服務(wù)的話蜡镶,那么這里實(shí)際上是另一個(gè)的低優(yōu)先級(jí)的過(guò)濾器來(lái)控制資源接口的雾袱,這些接口是被保護(hù)在了一個(gè)訪問(wèn)令牌(access token)中,所以請(qǐng)?zhí)暨x一個(gè)URL鏈接來(lái)確保你的資源接口中有一個(gè)不需要被保護(hù)的鏈接用來(lái)取得授權(quán)官还,就如上面示例中的 /login 鏈接芹橡,你需要在 WebSecurityConfigurer 配置對(duì)象中進(jìn)行設(shè)置。
令牌端點(diǎn)默認(rèn)也是受保護(hù)的望伦,不過(guò)這里使用的是基于 HTTP Basic Authentication 標(biāo)準(zhǔn)的驗(yàn)證方式來(lái)驗(yàn)證客戶端的林说,這在XML配置中是無(wú)法進(jìn)行設(shè)置的(所以它應(yīng)該被明確的保護(hù))。
在XML配置中可以使用 <authorization-server/> 元素標(biāo)簽來(lái)改變默認(rèn)的端點(diǎn)URLs屯伞,注意在配置 /check_token 這個(gè)鏈接端點(diǎn)的時(shí)候腿箩,使用 check-token-enabled 屬性標(biāo)記啟用。
強(qiáng)制使用SSL(Enforcing SSL):
使用簡(jiǎn)單的HTTP請(qǐng)求來(lái)進(jìn)行測(cè)試是可以的劣摇,但是如果你要部署到產(chǎn)品環(huán)境上的時(shí)候珠移,你應(yīng)該永遠(yuǎn)都使用SSL來(lái)保護(hù)授權(quán)服務(wù)器在與客戶端進(jìn)行通訊的時(shí)候進(jìn)行加密。你可以把授權(quán)服務(wù)應(yīng)用程序放到一個(gè)安全的運(yùn)行容器中,或者你可以使用一個(gè)代理钧惧,如果你設(shè)置正確了的話它們應(yīng)該工作的很好(這樣的話你就不需要設(shè)置任何東西了)暇韧。
但是也許你可能希望使用 Spring Security 的 requiresChannel() 約束來(lái)保證安全,對(duì)于授權(quán)端點(diǎn)來(lái)說(shuō)(還記得上面的列表嗎浓瞪,就是那個(gè) /authorize 端點(diǎn))懈玻,它應(yīng)該成為應(yīng)用程序安全連接的一部分,而對(duì)于 /token 令牌端點(diǎn)來(lái)說(shuō)的話追逮,它應(yīng)該有一個(gè)標(biāo)記被配置在 AuthorizationServerEndpointsConfigurer 配置對(duì)象中酪刀,你可以使用 sslOnly() 方法來(lái)進(jìn)行設(shè)置。當(dāng)然了,這兩個(gè)設(shè)置是可選的,不過(guò)在以上兩種情況中娶耍,會(huì)導(dǎo)致Spring Security 會(huì)把不安全的請(qǐng)求通道重定向到一個(gè)安全通道中奔滑。(譯者注:即將HTTP請(qǐng)求重定向到HTTPS請(qǐng)求上)。
自定義錯(cuò)誤處理(Error Handling):
端點(diǎn)實(shí)際上就是一個(gè)特殊的Controller定欧,它用于返回一些對(duì)象數(shù)據(jù)。
授權(quán)服務(wù)的錯(cuò)誤信息是使用標(biāo)準(zhǔn)的Spring MVC來(lái)進(jìn)行處理的,也就是 @ExceptionHandler 注解的端點(diǎn)方法荧库,你也可以提供一個(gè) WebResponseExceptionTranslator 對(duì)象。最好的方式是改變響應(yīng)的內(nèi)容而不是直接進(jìn)行渲染赵刑。
假如說(shuō)在呈現(xiàn)令牌端點(diǎn)的時(shí)候發(fā)生了異常分衫,那么異常委托了 HttpMessageConverters 對(duì)象(它能夠被添加到MVC配置中)來(lái)進(jìn)行輸出。假如說(shuō)在呈現(xiàn)授權(quán)端點(diǎn)的時(shí)候未通過(guò)驗(yàn)證般此,則會(huì)被重定向到 /oauth/error 即錯(cuò)誤信息端點(diǎn)中蚪战。whitelabel error (即Spring框架提供的一個(gè)默認(rèn)錯(cuò)誤頁(yè)面)錯(cuò)誤端點(diǎn)提供了HTML的響應(yīng),但是你大概可能需要實(shí)現(xiàn)一個(gè)自定義錯(cuò)誤頁(yè)面(例如只是簡(jiǎn)單的增加一個(gè) @Controller 映射到請(qǐng)求路徑上 @RequestMapping("/oauth/error"))铐懊。
映射用戶角色到權(quán)限范圍(Mapping User Roles to Scopes):
有時(shí)候限制令牌的權(quán)限范圍是很有用的邀桑,這不僅僅是針對(duì)于客戶端,你還可以根據(jù)用戶的權(quán)限來(lái)進(jìn)行限制科乎。如果你使用 DefaultOAuth2RequestFactory 來(lái)配置 AuthorizationEndpoint 的話你可以設(shè)置一個(gè)flag即 checkUserScopes=true來(lái)限制權(quán)限范圍壁畸,不過(guò)這只能匹配到用戶的角色。你也可以注入一個(gè) OAuth2RequestFactory 到 TokenEnpoint 中茅茂,不過(guò)這只能工作在 password 授權(quán)模式下捏萍。如果你安裝一個(gè) TokenEndpointAuthenticationFilter 的話,你只需要增加一個(gè)過(guò)濾器到 HTTP BasicAuthenticationFilter 后面即可玉吁。當(dāng)然了照弥,你也可以實(shí)現(xiàn)你自己的權(quán)限規(guī)則到 scopes 范圍的映射和安裝一個(gè)你自己版本的 OAuth2RequestFactory。AuthorizationServerEndpointConfigurer 配置對(duì)象允許你注入一個(gè)你自定義的 OAuth2RequestFactory进副,因此你可以使用這個(gè)特性來(lái)設(shè)置這個(gè)工廠對(duì)象这揣,前提是你使用 @EnableAuthorizationServer 注解來(lái)進(jìn)行配置(見上面介紹的授權(quán)服務(wù)配置)悔常。
二、資源服務(wù)配置:
一個(gè)資源服務(wù)(可以和授權(quán)服務(wù)在同一個(gè)應(yīng)用中给赞,當(dāng)然也可以分離開成為兩個(gè)不同的應(yīng)用程序)提供一些受token令牌保護(hù)的資源机打,Spring OAuth提供者是通過(guò)Spring Security authentication filter 即驗(yàn)證過(guò)濾器來(lái)實(shí)現(xiàn)的保護(hù),你可以通過(guò) @EnableResourceServer 注解到一個(gè) @Configuration 配置類上片迅,并且必須使用 ResourceServerConfigurer 這個(gè)配置對(duì)象來(lái)進(jìn)行配置(可以選擇繼承自 ResourceServerConfigurerAdapter 然后覆寫其中的方法残邀,參數(shù)就是這個(gè)對(duì)象的實(shí)例),下面是一些可以配置的屬性:
tokenServices:ResourceServerTokenServices 類的實(shí)例柑蛇,用來(lái)實(shí)現(xiàn)令牌服務(wù)芥挣。
resourceId:這個(gè)資源服務(wù)的ID,這個(gè)屬性是可選的耻台,但是推薦設(shè)置并在授權(quán)服務(wù)中進(jìn)行驗(yàn)證空免。
其他的拓展屬性例如 tokenExtractor 令牌提取器用來(lái)提取請(qǐng)求中的令牌。
請(qǐng)求匹配器盆耽,用來(lái)設(shè)置需要進(jìn)行保護(hù)的資源路徑蹋砚,默認(rèn)的情況下是受保護(hù)資源服務(wù)的全部路徑。
受保護(hù)資源的訪問(wèn)規(guī)則摄杂,默認(rèn)的規(guī)則是簡(jiǎn)單的身份驗(yàn)證(plain authenticated)坝咐。
其他的自定義權(quán)限保護(hù)規(guī)則通過(guò) HttpSecurity 來(lái)進(jìn)行配置。
@EnableResourceServer 注解自動(dòng)增加了一個(gè)類型為 OAuth2AuthenticationProcessingFilter 的過(guò)濾器鏈析恢,
在XML配置中墨坚,使用 <resource-server />標(biāo)簽元素并指定id為一個(gè)servlet過(guò)濾器就能夠手動(dòng)增加一個(gè)標(biāo)準(zhǔn)的過(guò)濾器鏈。
ResourceServerTokenServices 是組成授權(quán)服務(wù)的另一半映挂,如果你的授權(quán)服務(wù)和資源服務(wù)在同一個(gè)應(yīng)用程序上的話框杜,你可以使用 DefaultTokenServices ,這樣的話袖肥,你就不用考慮關(guān)于實(shí)現(xiàn)所有必要的接口的一致性問(wèn)題,這通常是很困難的振劳。如果你的資源服務(wù)器是分離開的椎组,那么你就必須要確保能夠有匹配授權(quán)服務(wù)提供的 ResourceServerTokenServices,它知道如何對(duì)令牌進(jìn)行解碼历恐。
在授權(quán)服務(wù)器上寸癌,你通常可以使用 DefaultTokenServices 并且選擇一些主要的表達(dá)式通過(guò) TokenStore(后端存儲(chǔ)或者本地編碼)弱贼。
RemoteTokenServices 可以作為一個(gè)替代蒸苇,它將允許資源服務(wù)器通過(guò)HTTP請(qǐng)求來(lái)解碼令牌(也就是授權(quán)服務(wù)的 /oauth/check_token 端點(diǎn))。如果你的資源服務(wù)沒有太大的訪問(wèn)量的話吮旅,那么使用RemoteTokenServices 將會(huì)很方便(所有受保護(hù)的資源請(qǐng)求都將請(qǐng)求一次授權(quán)服務(wù)用以檢驗(yàn)token值)溪烤,或者你可以通過(guò)緩存來(lái)保存每一個(gè)token驗(yàn)證的結(jié)果味咳。
使用授權(quán)服務(wù)的 /oauth/check_token 端點(diǎn)你需要將這個(gè)端點(diǎn)暴露出去,以便資源服務(wù)可以進(jìn)行訪問(wèn)檬嘀,這在咱們授權(quán)服務(wù)配置中已經(jīng)提到了槽驶,下面是一個(gè)例子:
@Overridepublicvoidconfigure(AuthorizationServerSecurityConfigurer oauthServer)throws Exception {
? ? oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')")
.checkTokenAccess(
"hasAuthority('ROLE_TRUSTED_CLIENT')");
}
在這個(gè)例子中,我們配置了 /oauth/check_token 和 /oauth/token_key 這兩個(gè)端點(diǎn)(受信任的資源服務(wù)能夠獲取到公有密匙鸳兽,這是為了驗(yàn)證JWT令牌)掂铐。這兩個(gè)端點(diǎn)使用了HTTP Basic Authentication 即HTTP基本身份驗(yàn)證,使用 client_credentials 授權(quán)模式可以做到這一點(diǎn)揍异。
配置OAuth-Aware表達(dá)式處理器(OAuth-Aware Expression Handler):
你也許希望使用 Spring Security's expression-based access control 來(lái)獲得一些優(yōu)勢(shì)全陨,一個(gè)表達(dá)式處理器會(huì)被注冊(cè)到默認(rèn)的 @EnableResourceServer 配置中,這個(gè)表達(dá)式包含了 #oauth2.clientHasRole衷掷,#oauth2.clientHasAnyRole 以及 #oauth2.denyClient 所提供的方法來(lái)幫助你使用權(quán)限角色相關(guān)的功能(在 OAuth2SecurityExpressionMethods 中有完整的列表)辱姨。
在XML配置中你可以注冊(cè)一個(gè) OAuth-Aware 表達(dá)式處理器即 <expression-handler />元素標(biāo)簽到 常規(guī)的 <http /> 安全配置上。