Spring Security OAuth2 開發(fā)指南
官方文檔 :http://projects.spring.io/spring-security-oauth/docs/oauth2.html
- Spring OAuth2.0 提供者:
授權(quán)服務(wù) Authorization Service.
資源服務(wù) Resource Service.
雖然這兩個提供者有時候可能存在同一個應(yīng)用程序中糯钙,但在Spring Security OAuth中你可以把 他它們各自放在不同的應(yīng)用上,而且你可以有多個資源服務(wù),它們共享同一個中央授權(quán)服務(wù)。
所有獲取令牌的請求都將會在Spring MVC controller endpoints中進行處理,并且訪問受保護 的資源服務(wù)的處理流程將會放在標(biāo)準(zhǔn)的Spring Security請求過濾器中肩碟。
配置一個授權(quán)服務(wù)必須要實現(xiàn)的endpoints:
AuthorizationEndpoint:用來作為請求者獲得授權(quán)的服務(wù),默認(rèn)的URL是/oauth/authorize. TokenEndpoint:用來作為請求者獲得令牌(Token)的服務(wù),默認(rèn)的URL是/oauth/token.
- 配置一個資源服務(wù)必須要實現(xiàn)的過濾器:
OAuth2AuthenticationProcessingFilter:用來作為認(rèn)證令牌(Token)的一個處理流程過濾器猬腰。只有當(dāng)過濾器通過之后,請求者才能獲得受保護的資源猜敢。
- 配置提供者(授權(quán)、資源)都可以通過簡單的Java注解@Configuration來進行適配,你也可以使用基于XML的聲明式語法來進行配置踱稍,如果你打算這樣做的話廊蜒,那么請使用http://www.springframework.org/schema/security/spring-security-oauth2.xsd來作為XML的schema(即XML概要定義)
以及使用http://www.springframework.org/schema/security/oauth2來作為命名空間。
@EnableAuthorizationServer 開啟授權(quán)服務(wù)配置胯盯,會配置授權(quán)服務(wù)必須的端點以及安全配置懈费。
@EnableResourceServer 開啟資源服務(wù)配置,會配置資源服務(wù)相關(guān)的安全配置博脑。
一憎乙、授權(quán)服務(wù)配置:
授權(quán)服務(wù)類型
- 配置一個授權(quán)服務(wù),你需要考慮幾種授權(quán)類型(Grant Type)叉趣,不同的授權(quán)類型為客戶端(Client)提供了不同的獲取令牌(Token)方式泞边,為了實現(xiàn)并確定這幾種授權(quán),需要配置使用 ClientDetailsService 和 TokenService 來開啟或者禁用這幾種授權(quán)機制疗杉。到這里就請注意了繁堡,不管你使用什么樣的授權(quán)類型(Grant Type),每一個客戶端(Client)都能夠通過明確的配置以及權(quán)限來實現(xiàn)不同的授權(quán)訪問機制。這也就是說椭蹄,假如你提供了一個支持"client_credentials"的授權(quán)方式闻牡,并不意味著客戶端就需要使用這種方式來獲得授權(quán)。下面是幾種授權(quán)類型的列表绳矩,具體授權(quán)機制的含義可以參見RFC6749(中文版本):
authorization_code:授權(quán)碼類型罩润。
implicit:隱式授權(quán)類型。
password:資源所有者(即用戶)密碼類型翼馆。
client_credentials:客戶端憑據(jù)(客戶端ID以及Key)類型割以。
refresh_token:通過以上授權(quán)獲得的刷新令牌來獲取新的令牌。
授權(quán)服務(wù)配置類
- 可以用 @EnableAuthorizationServer注解來配置OAuth2.0授權(quán)服務(wù)機制应媚,通過使用@Bean注解的幾個方法一起來配置這個授權(quán)服務(wù)严沥。下面咱們介紹幾個配置類,這幾個配置是由Spring創(chuàng)建的獨立的配置對象中姜,它們會被Spring傳入AuthorizationServerConfigurer中:
ClientDetailsServiceConfigurer:
用來配置客戶端詳情服務(wù)(ClientDetailsService)消玄,客戶端詳情信息在這里進行初始化,你能夠把客戶端詳情信息寫死在這里或者是通過數(shù)據(jù)庫來存儲調(diào)取詳情信息丢胚。
AuthorizationServerSecurityConfigurer:用來配置令牌端點(Token Endpoint)的安全約束.
AuthorizationServerEndpointsConfigurer:用來配置授權(quán)(authorization)以及令牌(token)的訪問端點和令牌服務(wù)(token services)翩瓜。
以上的配置可以選擇繼承AuthorizationServerConfigurerAdapter并且覆寫其中的三個configure方法來進行配置。
配置授權(quán)服務(wù)一個比較重要的方面就是提供一個授權(quán)碼給一個OAuth客戶端(通過authorization_code 授權(quán)類型)携龟,一個授權(quán)碼的獲取是OAuth客戶端跳轉(zhuǎn)到一個授權(quán)頁面兔跌,然后通過驗證授權(quán)之后服務(wù)器重定向到OAuth客戶端,并且在重定向連接中附帶返回一個授權(quán)碼峡蟋。
如果你是通過XML來進行配置的話坟桅,那么可以使用 <authorization-server/> 標(biāo)簽來進行配置。
想想現(xiàn)在國內(nèi)各大平臺的社會化登陸服務(wù)蕊蝗,例如騰訊桦卒,用戶要使用QQ登錄到某個網(wǎng)站,這個網(wǎng)站是跳轉(zhuǎn)到了騰訊的登陸授權(quán)頁面匿又,然后用戶登錄并且確定授權(quán)之后跳轉(zhuǎn)回目標(biāo)網(wǎng)站方灾,這種授權(quán)方式規(guī)范在我上面提供的鏈接RFC6749的第4.1節(jié)有詳細(xì)闡述。
- 配置客戶端詳情信息(Client Details):ClientDetailsServiceConfigurer (AuthorizationServerConfigurer 的一個回調(diào)配置項碌更,見上的概述) 能夠使用內(nèi)存或者JDBC來實現(xiàn)客戶端詳情服務(wù)(ClientDetailsService)裕偿,有幾個重要的屬性如下列表:
clientId:(必須的)用來標(biāo)識客戶的Id。
secret:(需要值得信任的客戶端)客戶端安全碼痛单,如果有的話嘿棘。
scope:用來限制客戶端的訪問范圍,如果為空(默認(rèn))的話旭绒,那么客戶端擁有全部的訪問范圍鸟妙。 authorizedGrantTypes:此客戶端可以使用的授權(quán)類型焦人,默認(rèn)為空。
authorities:此客戶端可以使用的權(quán)限(基于Spring Security authorities)重父。
客戶端詳情(Client Details)
- 能夠在應(yīng)用程序運行的時候進行更新花椭,可以通過訪問底層的存儲服務(wù)(例如將客戶端詳情存儲在一個關(guān)系數(shù)據(jù)庫的表中,就可以使用JdbcClientDetailsService)或者通過 ClientDetailsManager接口(同時你也可以實現(xiàn)ClientDetailsService接口)來進行管理房午。
(譯者注:不過我并沒有找到 ClientDetailsManager 這個接口文件矿辽,只找到了 ClientDetailsService)
管理令牌(Managing Token)
- AuthorizationServerTokenServices接口定義了一些操作使得你可以對令牌進行一些必要的管理,在使用這些操作的時候請注意以下幾點:
1)當(dāng)一個令牌被創(chuàng)建了郭厌,你必須對其進行保存袋倔,這樣當(dāng)一個客戶端使用這個令牌對資源服務(wù)進行請求的時候才能夠引用這個令牌。
2)當(dāng)一個令牌是有效的時候折柠,它可以被用來加載身份信息宾娜,里面包含了這個令牌的相關(guān)權(quán)限。
3)當(dāng)你自己創(chuàng)建 AuthorizationServerTokenServices這個接口的實現(xiàn)時扇售,你可能需要考慮一下使用 DefaultTokenServices這個類前塔,里面包含了一些有用實現(xiàn),你可以使用它來修改令牌的格式和令牌的存儲缘眶。默認(rèn)的,當(dāng)它嘗試創(chuàng)建一個令牌的時候髓废,是使用隨機值來進行填充的巷懈,除了持久化令牌是委托一個 TokenStore接口來實現(xiàn)以外,這個類幾乎幫你做了所有的事情慌洪。并且 TokenStore 這個接口有一個默認(rèn)的實現(xiàn)顶燕,它就是InMemoryTokenStore,如其命名冈爹,所有的令牌是被保存在了內(nèi)存中涌攻。除了使用這個類以外,你還可以使用一些其他的預(yù)定義實現(xiàn)频伤,下面有幾個版本恳谎,它們都實現(xiàn)了TokenStore接口:
InMemoryTokenStore:這個版本的實現(xiàn)是被默認(rèn)采用的,它可以完美的工作在單服務(wù)器上(即訪問并發(fā)量壓力不大的情況下憋肖,并且它在失敗的時候不會進行備份)因痛,大多數(shù)的項目都可以使用這個版本的實現(xiàn)來進行嘗試,你可以在開發(fā)的時候使用它來進行管理岸更,因為不會被保存到磁盤中鸵膏,所以更易于調(diào)試。
JdbcTokenStore:這是一個基于JDBC的實現(xiàn)版本怎炊,令牌會被保存進關(guān)系型數(shù)據(jù)庫谭企。使用這個版本的實現(xiàn)時廓译,你可以在不同的服務(wù)器之間共享令牌信息,使用這個版本的時候請注意把"spring-jdbc"這個依賴加入到你的classpath當(dāng)中债查。
JwtTokenStore:這個版本的全稱是 JSON Web Token(JWT)非区,它可以把令牌相關(guān)的數(shù)據(jù)進行編碼(因此對于后端服務(wù)來說,它不需要進行存儲攀操,這將是一個重大優(yōu)勢)院仿,但是它有一個缺點,那就是撤銷一個已經(jīng)授權(quán)令牌將會非常困難速和,所以它通常用來處理一個生命周期較短的令牌以及撤銷刷新令牌(refresh_token)歹垫。另外一個缺點就是這個令牌占用的空間會比較大,如果你加入了比較多用戶憑證信息颠放。JwtTokenStore 不會保存任何數(shù)據(jù)排惨,但是它在轉(zhuǎn)換令牌值以及授權(quán)信息方面與 DefaultTokenServices 所扮演的角色是一樣的。
JWT令牌(JWT Tokens)
使用JWT令牌你需要在授權(quán)服務(wù)中使用JwtTokenStore碰凶,資源服務(wù)器也需要一個解碼的Token令牌的類 JwtAccessTokenConverter暮芭,JwtTokenStore依賴這個類來進行編碼以及解碼,因此你的授權(quán)服務(wù)以及資源服務(wù)都需要使用這個轉(zhuǎn)換類欲低。Token令牌默認(rèn)是有簽名的辕宏,并且資源服務(wù)需要驗證這個簽名,因此呢砾莱,你需要使用一個對稱的Key值瑞筐,用來參與簽名計算,這個Key值存在于授權(quán)服務(wù)以及資源服務(wù)之中腊瑟。\
或者你可以使用非對稱加密算法來對Token進行簽名聚假,Public Key公布在/oauth/token_key這個URL連接中,默認(rèn)的訪問安全規(guī)則是"denyAll()"闰非,即在默認(rèn)的情況下它是關(guān)閉的膘格,你可以注入一個標(biāo)準(zhǔn)的 SpEL 表達式到 AuthorizationServerSecurityConfigurer 這個配置中來將它開啟(例如使用"permitAll()"來開啟可能比較合適,因為它是一個公共密鑰)财松。
/**
* 授權(quán)服務(wù)器端點的安全配置
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("permitAll()")
// 讓/oauth/token支持client_id以及client_secret作登錄認(rèn)證
.allowFormAuthenticationForClients();
}
如果你要使用 JwtTokenStore瘪贱,請務(wù)必把"spring-security-jwt"這個依賴加入到你的classpath中。
配置授權(quán)類型(Grant Types)
- 授權(quán)是使用 AuthorizationEndpoint這個端點來進行控制的辆毡,你能夠使用AuthorizationServerEndpointsConfigurer 這個對象的實例來進行配置(AuthorizationServerConfigurer的一個回調(diào)配置項政敢,見上的概述) ,如果你不進行設(shè)置的話胚迫,默認(rèn)是除了資源所有者密碼(password)授權(quán)類型以外喷户,支持其余所有標(biāo)準(zhǔn)授權(quán)類型的(RFC6749),我們來看一下這個配置對象有哪些屬性可以設(shè)置吧访锻,如下列表:
authenticationManager:認(rèn)證管理器褪尝,當(dāng)你選擇了資源所有者密碼(password)授權(quán)類型的時候闹获,請設(shè)置這個屬性注入一個 AuthenticationManager 對象。
userDetailsService:如果你設(shè)置了這個屬性的話河哑,那說明你有一個自己的UserDetailsService 接口的實現(xiàn)避诽,或者你可以把這個東西設(shè)置到全局域上面去(例如GlobalAuthenticationManagerConfigurer 這個配置對象),當(dāng)你設(shè)置了這個之后璃谨,那么"refresh_token"即刷新令牌授權(quán)類型模式的流程中就會包含一個檢查沙庐,用來確保這個賬號是否仍然有效,假如說你禁用了這個賬戶的話佳吞。
authorizationCodeServices:這個屬性是用來設(shè)置授權(quán)碼服務(wù)的(即AuthorizationCodeServices 的實例對象)拱雏,主要用于 "authorization_code" 授權(quán)碼類型模式。
mplicitGrantService:這個屬性用于設(shè)置隱式授權(quán)模式底扳,用來管理隱式授權(quán)模式的狀態(tài)铸抑。
tokenGranter:這個屬性就很牛B了,當(dāng)你設(shè)置了這個東西(即TokenGranter接口實現(xiàn))衷模,那么授權(quán)將會交由你來完全掌控鹊汛,并且會忽略掉上面的這幾個屬性,這個屬性一般是用作拓展用途的阱冶,即標(biāo)準(zhǔn)的四種授權(quán)模式已經(jīng)滿足不了你的需求的時候刁憋,才會考慮使用這個。
- 在XML配置中呢木蹬,你可以使用 "authorization-server" 這個標(biāo)簽元素來進行設(shè)置至耻。
配置授權(quán)端點的URL(Endpoint URLs):
- AuthorizationServerEndpointsConfigurer這個配置對象(AuthorizationServerConfigurer的一個回調(diào)配置項,見上的概述)有一個叫做pathMapping()的方法用來配置端點URL鏈接届囚,它有兩個參數(shù):
第一個參數(shù):String 類型的有梆,這個端點URL的默認(rèn)鏈接是尖。
第二個參數(shù):String 類型的意系,你要進行替代的URL鏈接。
- 以上的參數(shù)都將以 "/"字符為開始的字符串饺汹,框架的默認(rèn)URL鏈接如下列表蛔添,可以作為這個pathMapping() 方法的第一個參數(shù):
/oauth/authorize:授權(quán)端點。
/oauth/token:令牌端點兜辞。
/oauth/confirm_access:用戶確認(rèn)授權(quán)提交端點迎瞧。
/oauth/error:授權(quán)服務(wù)錯誤信息端點。
/oauth/check_token:用于資源服務(wù)訪問的令牌解析端點逸吵。
/oauth/token_key:提供公有密匙的端點凶硅,如果你使用JWT令牌的話。
- 需要注意的是授權(quán)端點這個URL應(yīng)該被SpringSecurity保護起來只供授權(quán)用戶訪問扫皱,我們來看看在標(biāo)準(zhǔn)的Spring Security中 WebSecurityConfigurer 是怎么用的足绅。
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
//default protection for all resources (including /oauth/authorize)
.and().authorizeRequests().anyRequest().hasRole("USER")
//... more configuration, e.g. for form login
}
注意:如果你的應(yīng)用程序中既包含授權(quán)服務(wù)又包含資源服務(wù)的話,那么這里實際上是另一個的低優(yōu)先級的過濾器來控制資源接口的捷绑,
這些接口是被保護在了一個訪問令牌(access token)中, 所以請?zhí)暨x一個URL鏈接來確保你的資源接口中有一個不需要被保護的鏈接用來取得授權(quán)氢妈,
就如上面示例中的 /login 鏈接粹污,你需要在 WebSecurityConfigurer 配置對象中進行設(shè)置。
令牌端點默認(rèn)也是受保護的首量,不過這里使用的是基于 HTTP Basic Authentication標(biāo)準(zhǔn)的驗證方式來驗證客戶端的壮吩,這在XML配置中是無法進行設(shè)置的(所以它應(yīng)該被明確的保護)。
在XML配置中可以使用 <authorization-server/> 元素標(biāo)簽來改變默認(rèn)的端點URLs加缘,注意在配置 /check_token 這個鏈接端點的時候鸭叙,使用 check-token-enabled 屬性標(biāo)記啟用。
強制使用SSL(Enforcing SSL):
使用簡單的HTTP請求來進行測試是可以的生百,但是如果你要部署到產(chǎn)品環(huán)境上的時候递雀,你應(yīng)該永遠(yuǎn)都使用SSL來保護授權(quán)服務(wù)器在與客戶端進行通訊的時候進行加密。
你可以把授權(quán)服務(wù)應(yīng)用程序放到一個安全的運行容器中蚀浆,或者你可以使用一個代理缀程,如果你設(shè)置正確了的話它們應(yīng)該工作的很好(這樣的話你就不需要設(shè)置任何東西了)。
但是也許你可能希望使用Spring Security的requiresChannel()約束來保證安全市俊,對于授權(quán)端點來說(還記得上面的列表嗎杨凑,就是那個 /authorize 端點),它應(yīng)該成為應(yīng)用程序安全連接的一部分摆昧,而對于 /token 令牌端點來說的話撩满,它應(yīng)該有一個標(biāo)記被配置在 AuthorizationServerEndpointsConfigurer 配置對象中,你可以使用sslOnly()方法來進行設(shè)置绅你。當(dāng)然了伺帘,這兩個設(shè)置是可選的,不過在以上兩種情況中忌锯,會導(dǎo)致Spring Security會把不安全的請求通道重定向到一個安全通道中伪嫁。(譯者注:即將HTTP請求重定向到HTTPS請求上)。
自定義錯誤處理(Error Handling):
端點實際上就是一個特殊的Controller偶垮,它用于返回一些對象數(shù)據(jù)张咳。
授權(quán)服務(wù)的錯誤信息是使用標(biāo)準(zhǔn)的Spring MVC來進行處理的,也就是 @ExceptionHandler 注解的端點方法似舵,你也可以提供一個 WebResponseExceptionTranslator 對象脚猾。
最好的方式是改變響應(yīng)的內(nèi)容而不是直接進行渲染。假如說在呈現(xiàn)令牌端點的時候發(fā)生了異常砚哗,那么異常委托了 HttpMessageConverters對象(它能夠被添加到MVC配置中)來進行輸出龙助。假如說在呈現(xiàn)授權(quán)端點的時候未通過驗證,則會被重定向到 /oauth/error 即錯誤信息端點中蛛芥。whitelabel error (即Spring框架提供的一個默認(rèn)錯誤頁面)錯誤端點提供了HTML的響應(yīng)提鸟,但是你大概可能需要實現(xiàn)一個自定義錯誤頁面(例如只是簡單的增加一個 @Controller 映射到請求路徑上 @RequestMapping("/oauth/error"))脆淹。
映射用戶角色到權(quán)限范圍(Mapping User Roles to Scopes):
有時候限制令牌的權(quán)限范圍是很有用的,這不僅僅是針對于客戶端沽一,你還可以根據(jù)用戶的權(quán)限來進行限制盖溺。如果你使用 DefaultOAuth2RequestFactory 來配置 AuthorizationEndpoint 的話你可以設(shè)置一個flag即 checkUserScopes=true來限制權(quán)限范圍,不過這只能匹配到用戶的角色铣缠。你也可以注入一個 OAuth2RequestFactory 到 TokenEnpoint 中烘嘱,不過這只能工作在 password 授權(quán)模式下。如果你安裝一個 TokenEndpointAuthenticationFilter 的話蝗蛙,你只需要增加一個過濾器到 HTTP BasicAuthenticationFilter 后面即可蝇庭。當(dāng)然了,你也可以實現(xiàn)你自己的權(quán)限規(guī)則到 scopes 范圍的映射和安裝一個你自己版本的 OAuth2RequestFactory捡硅。
AuthorizationServerEndpointConfigurer 配置對象允許你注入一個你自定義的 OAuth2RequestFactory哮内,因此你可以使用這個特性來設(shè)置這個工廠對象,前提是你使用 @EnableAuthorizationServer 注解來進行配置(見上面介紹的授權(quán)服務(wù)配置)壮韭。
二北发、資源服務(wù)配置:
- 一個資源服務(wù)(可以和授權(quán)服務(wù)在同一個應(yīng)用中,當(dāng)然也可以分離開成為兩個不同的應(yīng)用程序)提供一些受token令牌保護的資源喷屋,Spring OAuth提供者是通過Spring Security authentication filter 即驗證過濾器來實現(xiàn)的保護琳拨,你可以通過 @EnableResourceServer 注解到一個 @Configuration 配置類上,并且必須使用 ResourceServerConfigurer 這個配置對象來進行配置(可以選擇繼承自ResourceServerConfigurerAdapter 然后覆寫其中的方法屯曹,參數(shù)就是這個對象的實例)狱庇,下面是一些可以配置的屬性:
tokenServices:ResourceServerTokenServices 類的實例,用來實現(xiàn)令牌服務(wù)恶耽。
resourceId:這個資源服務(wù)的ID密任,這個屬性是可選的,但是推薦設(shè)置并在授權(quán)服務(wù)中進行驗證偷俭。
tokenExtractor 令牌提取器用來提取請求中的令牌浪讳。
請求匹配器,用來設(shè)置需要進行保護的資源路徑社搅,默認(rèn)的情況下是受保護資源服務(wù)的全部路徑驻债。
受保護資源的訪問規(guī)則乳规,默認(rèn)的規(guī)則是簡單的身份驗證(plain authenticated)形葬。
其他的自定義權(quán)限保護規(guī)則通過 HttpSecurity 來進行配置。
@EnableResourceServer 注解自動增加了一個類型為 OAuth2AuthenticationProcessingFilter 的過濾器鏈暮的,
在XML配置中笙以,使用 <resource-server/>標(biāo)簽元素并指定id為一個servlet過濾器就能夠手動增加一個標(biāo)準(zhǔn)的過濾器鏈。
ResourceServerTokenServices是組成授權(quán)服務(wù)的另一半(token的解析)冻辩,如果你的授權(quán)服務(wù)和資源服務(wù)在同一個應(yīng)用程序上的話猖腕,你可以使用DefaultTokenServices拆祈,這樣的話,你就不用考慮關(guān)于實現(xiàn)所有必要的接口的一致性問題倘感,這通常是很困難的放坏。如果你的資源服務(wù)器是分離開的,那么你就必須要確保能夠有匹配授權(quán)服務(wù)提供的ResourceServerTokenServices老玛,它知道如何對令牌進行解碼淤年。
在授權(quán)服務(wù)器上,你通忱可以使用DefaultTokenServices并且選擇一些主要的表達式通過TokenStore(后端存儲或者本地編碼)麸粮。
RemoteTokenServices 可以作為一個替代,它將允許資源服務(wù)器通過HTTP請求來解碼令牌(也就是授權(quán)服務(wù)的 /oauth/check_token端點)镜廉。如果你的資源服務(wù)沒有太大的訪問量的話弄诲,那么使用RemoteTokenServices 將會很方便(所有受保護的資源請求都將請求一次授權(quán)服務(wù)用以檢驗token值),或者你可以通過緩存來保存每一個token驗證的結(jié)果娇唯。
使用授權(quán)服務(wù)的/oauth/check_token端點你需要將這個端點暴露出去齐遵,以便資源服務(wù)可以進行訪問,這在咱們授權(quán)服務(wù)配置中已經(jīng)提到了塔插,下面是另外一個例子:
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')")
.checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}
- 在這個例子中洛搀,我們配置了/oauth/check_token和/oauth/token_key這兩個端點(受信任的資源服務(wù)能夠獲取到公有密匙,這是為了驗證JWT令牌)佑淀。這兩個端點使用了HTTP Basic Authentication 即HTTP基本身份驗證留美,使用 client_credentials 授權(quán)模式可以做到這一點。
配置OAuth-Aware表達式處理器(OAuth-Aware Expression Handler):
你也許希望使用 Spring Security's expression-based access control 來獲得一些優(yōu)勢伸刃,一個表達式處理器會被注冊到默認(rèn)的 @EnableResourceServer 配置中谎砾,這個表達式包含了 #oauth2.clientHasRole,#oauth2.clientHasAnyRole 以及 oauth2.denyClient 所提供的方法來幫助你使用權(quán)限角色相關(guān)的功能(在 OAuth2SecurityExpressionMethods 中有完整的列表)捧颅。
在XML配置中你可以注冊一個 OAuth-Aware 表達式處理器即 <expression-handler />元素標(biāo)簽到 常規(guī)的 <http /> 安全配置上景图。
OAuth2.0 客戶端
- OAuth 2.0 客戶端控制著OAuth2.0保護的其它服務(wù)器的資源的訪問權(quán)限。配置包括建立相關(guān)受保護資源與有權(quán)限訪問資源的用戶之間的連接碉哑≈勘遥客戶端也需要實現(xiàn)存儲用戶的授權(quán)代碼和訪問令牌的功能。
受保護資源的配置
- 受保護的資源(或稱為遠(yuǎn)程資源)可以使用OAuth2ProtectedResourceDetails類型的實體bean定義扣典。 一個受保護的資源有以下屬性:
id:資源id妆毕。它僅在客戶端搜索資源的時候使用;在OAuth協(xié)議中它從未被用到贮尖。它也被用作bean的id笛粘。
clientId:OAuth客戶端id。OAuth提供端依賴這個id來識別客戶端。
clientSecret:與資源有關(guān)的秘密薪前。默認(rèn)情況下润努,該值不為空。
accessTokenUri:提供訪問口令的OAuth提供者終端的統(tǒng)一資源標(biāo)識符(URI)示括。
scope:以逗號分隔的字符串列表铺浇,標(biāo)識可訪問資源的范圍。默認(rèn)情況下垛膝,該值為空随抠。
clientAuthenticationScheme: 客戶端對訪問的令牌終端授權(quán)時使用的機制。
建議值: "http_basic" 和 "form"繁涂。 默認(rèn)值: "http_basic"拱她。 見OAuth 2 幫助文檔2.1節(jié)。
- 不同的授權(quán)類型有不同的實現(xiàn)OAuth2ProtectedResourceDetails (對于client_credentials授權(quán)類型扔罪,使用ClientCredentialsResource )的方式秉沼。對于需要進行用戶身份驗證的授權(quán)類型,還有一個屬性:
userAuthorizationUri: 用戶訪問資源需要身份驗證時跳轉(zhuǎn)頁面的URI矿酵。 注意這個字段不是必填的唬复,它依賴于被支持的OAuth 2的配置文件類型。
在XML中全肮,可以使用<resource/>元素創(chuàng)建一個OAuth2ProtectedResourceDetails類型的實體bean敞咧。 它有上面提到的所有的屬性。
使用@EnableOAuth2Client對OAuth2.0的客戶端的配置比較簡單辜腺。主要要做兩件事情:
創(chuàng)建一個過濾bean(用oauth2ClientContextFilter)來存儲當(dāng)前的請求和上下文休建。在這種情況下需要在請求期間授權(quán),來管理從重定向的位置和OAuth已認(rèn)證的url评疗。
在請求作用域中創(chuàng)建一個AccessTokenRequest類型的bean测砂。這個類型的bean可以在個人用戶的沖突中被識別碼識別(或隱式的),授權(quán)客戶端保持授權(quán)狀態(tài)百匆。
這個過濾器需要能夠連接到應(yīng)用(例如砌些,使用Servlet初始化程序或者web.xml配置文件配置 一個和DelegatingFilterProxy相同名稱的代理)。
在一個OAuth2RestTemplate中AccessTokenRequest可以這樣使用:
@Autowired
private OAuth2ClientContext oauth2Context;
@Bean
public OAuth2RestTemplate sparklrRestTemplate() {
return new OAuth2RestTemplate(sparklr(), oauth2Context);
}
OAuth2ClientContext可以在Session的作用域中保持不同用戶不同的狀態(tài)加匈。如果沒有這個功能存璃,你需要在你自己的服務(wù)強上管理等效的數(shù)據(jù)結(jié)構(gòu),映射不用用戶進來的請求并且用相互隔離的OAuth2ClientContext實例連接各個用戶雕拼。
在XML文件中纵东,有一個帶有id屬性的<client/>標(biāo)簽用于表示servlet的Filter的bean id,這個必須映射成一個和DelegatingFilterProxy有相同名稱的@Configuration注解悲没。
訪問受保護的資源
- 一旦篮迎,你已經(jīng)提供了所有的資源服務(wù)器配置時,現(xiàn)在你可以訪問這些資源示姿。建議的訪問這些資源是通過使用在Spring3中提到的RestTemplate甜橱。Spring Security OAuth已經(jīng)提供了一個擴展的RestTemplate,只需要提供一個OAuth2ProtectedResourceDetails的實例栈戳。使用它與user-tokens(授權(quán)代碼授予)你應(yīng)該考慮使用@EnableOAuth2Client配置(或XML等價< oauth:rest-template / >),造成了一些請求和會話作用域上下文對象,要求不同的用戶在運行時不發(fā)生沖突岂傲。
客戶端持久化訪問令牌
- 客戶端不需要持久化令牌,但是如果客戶端重啟又不想重新去請求令牌,就需要持久化令牌。
- ClientTokenServices接口定義所需的令牌持久化的操作子檀。提供一個JDBC實現(xiàn),但是如果你喜歡的話你可以實現(xiàn)自己的服務(wù)以存儲訪問令牌以及相關(guān)的認(rèn)證實例镊掖。如果你想使用此功能,你需要提供一個專門的TokenProvider給OAuth2RestTemplate幔欧。如:
@Bean@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2RestOperations restTemplate() {
OAuth2RestTemplate template = new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(accessTokenRequest));
AccessTokenProviderChain provider = new AccessTokenProviderChain(Arrays.asList(new AuthorizationCodeAccessTokenProvider()));
provider.setClientTokenServices(clientTokenServices());
return template;
}
為外部 OAuth2 提供者定制客戶端
一些外部OAuth2提供商(如Facebook)不完全實現(xiàn)正確規(guī)范,否則他們只是困在一個舊版本比Spring Security OAuth的規(guī)范季二。在您的客戶機應(yīng)用程序使用這些供應(yīng)商可能需要適應(yīng)客戶端基礎(chǔ)設(shè)施的各個部分男旗。
使用Facebook作為一個例子,有一個Facebook功能tonr2應(yīng)用程序(您需要更改配置添加你自己的,有效的,客戶機id和秘密,他們很容易生成在Facebook網(wǎng)站上)摊灭。
Facebook響應(yīng)令牌也包含一個不一致的洪囤、有失效時間的JSON實體(他們使用到期而不是expires_in),所以如果你想在應(yīng)用程序中使用失效時間你將不得不使用一個自定義OAuth2SerializationService手動解碼渐行。