Spring Security OAuth 2開發者指南譯

介紹

這是用戶指南的支持OAuth 2.0。對於OAuth 1.0,一切都是不一樣的,因此看到它的用戶指南html

本用戶指南分爲兩部分,第一部分爲OAuth 2.0提供者,第二部分爲OAuth 2.0客戶端。對於提供商和客戶端,示例代碼的最佳來源是集成測試示例應用程序java

OAuth 2.0提供程序

OAuth 2.0提供者機制負責公開OAuth 2.0受保護的資源。該配置包括創建可獨立或表明用戶訪問其受保護資源的OAuth 2.0客戶端。提供者經過管理和驗證用於訪問受保護資源的OAuth 2.0令牌來實現。在適用的狀況下,提供商還必須提供用戶界面,以確認客戶端能夠被受權訪問受保護資源(即確認頁面)。git

OAuth 2.0提供程序實現

OAuth 2.0中的提供者角色其實是在受權服務和資源服務之間分割的,而有時它們位於同一個應用程序中,使用Spring Security OAuth,您能夠選擇在兩個應用程序之間進行拆分,而且還能夠共享多個資源服務受權服務。令牌的請求由Spring MVC控制器端點處理,對受保護資源的訪問由標準的Spring Security請求過濾器處理。爲了實現OAuth 2.0受權服務器,Spring Security過濾器鏈中須要如下端點:github

實施OAuth 2.0資源服務器須要如下過濾器:web

對於全部OAuth 2.0提供程序功能,使用特殊的Spring OAuth @Configuration適配器簡化了配置。還有一個用於OAuth配置的XML命名空間,而且模式位於www.springframework.org/schema/secu…。命名空間是http://www.springframework.org/schema/security/oauth2spring

受權服務器配置

在配置受權服務器時,必須考慮客戶端用於從最終用戶獲取訪問令牌(例如受權代碼,用戶憑據,刷新令牌)的受權類型。服務器的配置用於提供客戶端詳細信息服務和令牌服務的實現,而且啓用或禁用全局機制的某些方面。可是請注意,每一個客戶端均可以特別配置,以便可以使用某些受權機制和訪問受權。也就是由於您的提供商配置爲支持「客戶端憑據」受權類型,並不意味着特定客戶端被受權使用該受權類型。sql

@EnableAuthorizationServer註釋用於配置OAuth 2.0受權服務器機制,以及任何@Beans實現AuthorizationServerConfigurer(有一個方便的適配器實現)。將如下功能委派給由Spring建立並傳遞到如下內容的單獨配置程序AuthorizationServerConfigurer數據庫

  • ClientDetailsServiceConfigurer:一個定義客戶端詳細信息服務的配置程序。客戶端的詳細信息能夠初始化,也能夠參考現有的存儲。
  • AuthorizationServerSecurityConfigurer:定義令牌端點上的安全約束。
  • AuthorizationServerEndpointsConfigurer:定義受權和令牌端點和令牌服務。

提供商配置的一個重要方面是受權代碼提供給OAuth客戶端(受權代碼受權)的方式。受權代碼由OAuth客戶端經過將最終用戶指向用戶能夠輸入其憑據的受權頁面得到,致使從提供商受權服務器重定向到具備受權碼的OAuth客戶端。這在OAuth 2規範中有詳細說明。express

在XML中,有一個<authorization-server/>元素以相似的方式用於配置OAuth 2.0受權服務器。後端

配置客戶端詳細信息

ClientDetailsServiceConfigurer(從您的回調AuthorizationServerConfigurer)能夠用來在內存或JDBC實現客戶的細節服務來定義的。客戶端的重要屬性是

  • clientId:(必填)客戶端ID。
  • secret:(可信客戶端須要)客戶機密碼(若是有)。
  • scope:客戶受限的範圍。若是範圍未定義或爲空(默認值),客戶端不受範圍限制。
  • authorizedGrantTypes:授予客戶端使用受權的類型。默認值爲空。
  • authorities授予客戶的受權機構(普通的Spring Security權威機構)。

客戶端的詳細信息能夠經過直接訪問底層商店(例如,在數據庫表中JdbcClientDetailsService)或經過ClientDetailsManager接口(這兩種實現ClientDetailsService也實現)來更新運行的應用程序。

注意:JDBC服務的架構未與庫一塊兒打包(由於在實踐中可能須要使用太多變體),而是能夠從github中的測試代碼中開始。

管理令牌

AuthorizationServerTokenServices接口定義了所必需的管理OAuth 2.0令牌的操做。請注意如下事項:

  • 當建立訪問令牌時,必須存儲身份驗證,以便接受訪問令牌的資源能夠稍後引用。
  • 訪問令牌用於加載用於受權其建立的認證。

在建立AuthorizationServerTokenServices實現時,您可能須要考慮使用DefaultTokenServices可插入的策略來更改訪問令牌的格式和存儲。默認狀況下,它將經過隨機值建立令牌,並處理除表明它的令牌持久化以外的全部內容TokenStore。默認存儲是內存中的實現,但還有一些其餘可用的實現。這是一個關於每個的一些討論的描述

  • 默認值InMemoryTokenStore對於單個服務器是徹底正常的(即,在發生故障的狀況下,低流量和熱備份備份服務器)。大多數項目能夠從這裏開始,也能夠在開發模式下運行,以便輕鬆啓動沒有依賴關係的服務器。
  • JdbcTokenStore是同一件事的JDBC版本,它將令牌數據存儲在關係數據庫中。若是您能夠在服務器之間共享數據庫,則可使用JDBC版本,若是隻有一個,則擴展同一服務器的實例,或者若是有多個組件,則受權和資源服務器。要使用JdbcTokenStore你須要「spring-jdbc」的類路徑。
  • 商店的JSON Web令牌(JWT)版本將全部關於受權的數據編碼到令牌自己(所以,根本沒有後端存儲是一個顯着的優點)。一個缺點是您不能輕易地撤銷訪問令牌,所以一般被授予短時間到期權,撤銷在刷新令牌處理。另外一個缺點是,若是您在其中存儲了大量用戶憑據信息,令牌可能會變得很是大。這JwtTokenStore不是一個真正的「商店」,由於它不會保留任何數據,但它在翻譯令牌值和驗證信息之間起着相同的做用DefaultTokenServices

注意:JDBC服務的架構未與庫一塊兒打包(由於在實踐中可能須要使用太多變體),而是能夠從github中的測試代碼中開始。確保@EnableTransactionManagement在建立令牌時,防止在競爭相同行的客戶端應用程序之間發生衝突。還要注意,示例模式有明確的PRIMARY KEY聲明 - 這些在併發環境中也是必需的。

JWT令牌

要使用JWT令牌,您須要JwtTokenStore在受權服務器中。資源服務器還須要可以對令牌進行解碼,所以它JwtTokenStore具備依賴性JwtAccessTokenConverter,而且受權服務器和資源服務器都須要相同的實現。默認狀況下,令牌被簽名,資源服務器還必須可以驗證簽名,所以它須要與受權服務器(共享密鑰或對稱密鑰)相同的對稱(簽名)密鑰,或者須要公共密鑰(驗證者密鑰),其與受權服務器中的私鑰(簽名密鑰)匹配(公私屬或非對稱密鑰)。公鑰(若是可用)由/oauth/token_key端點上的受權服務器公開,默認狀況下,訪問規則爲「denyAll()」。AuthorizationServerSecurityConfigurer

要使用JwtTokenStore你須要的「spring-security-jwt」你的類路徑(你能夠在與Spring OAuth相同的github倉庫中找到它,但發行週期不一樣)。

贈款類型

AuthorizationEndpoint能夠經過如下方式配置支持的受權類型AuthorizationServerEndpointsConfigurer。默認狀況下,全部受權類型均受支持,除了密碼(有關如何切換它的詳細信息,請參見下文)。如下屬性會影響受權類型:

  • authenticationManager:經過注入密碼受權被打開AuthenticationManager
  • userDetailsService:若是您注入UserDetailsService或者全局配置(例如a GlobalAuthenticationManagerConfigurer),則刷新令牌受權將包含對用戶詳細信息的檢查,以確保該賬戶仍然活動
  • authorizationCodeServices:定義AuthorizationCodeServices受權代碼受權的受權代碼服務(實例)。
  • implicitGrantService:在批准期間管理狀態。
  • tokenGranter:(TokenGranter徹底控制授予和忽略上述其餘屬性)

在XML授予類型中包含做爲子元素authorization-server

配置端點URL

AuthorizationServerEndpointsConfigurer有一個pathMapping()方法。它有兩個參數:

  • 端點的默認(框架實現)URL路徑
  • 須要的自定義路徑(以「/」開頭)

由框架提供的URL路徑/oauth/authorize(受權端點)/oauth/token(令牌端點)/oauth/confirm_access(用戶發佈批准此處)/oauth/error(用於在受權服務器中呈現錯誤)/oauth/check_token(由資源服務器用於解碼訪問令牌) ,而且/oauth/token_key(若是使用JWT令牌,則公開用於令牌驗證的公鑰)。

注意,受權端點/oauth/authorize(或其映射替代方案)應使用Spring Security進行保護,以便只有通過身份驗證的用戶才能訪問。例如使用標準的Spring Security WebSecurityConfigurer

@Override
    protected void configure(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
    }
複製代碼

注意:若是您的受權服務器也是資源服務器,那麼還有另外一個優先級較低的安全過濾器鏈控制API資源。經過訪問令牌來保護這些請求,您須要他們的路徑與主用戶面臨的過濾器鏈中的路徑匹配,所以請務必包含僅在WebSecurityConfigurer上述中選擇非API資源的請求匹配器。

默認狀況下,經過Spring OAuth在@Configuration使用客戶機密碼的HTTP Basic認證的支持中爲您保護令牌端點。在XML中不是這樣(所以應該明確保護)。

在XML中,<authorization-server/>元素具備一些能夠用於以相似方式更改默認端點URL的屬性。該/check_token端點必須(與顯式啓用check-token-enabled屬性)。

自定義UI

大多數受權服務器端點主要由機器使用,可是有一些資源須要一個UI,而這些資源是GET /oauth/confirm_access和HTML響應/oauth/error。它們是在框架中使用白名單實現提供的,所以受權服務器的大多數真實世界實例都但願提供本身的實例,以便他們能夠控制樣式和內容。全部您須要作的是@RequestMappings爲這些端點提供一個Spring MVC控制器,而且框架默認在調度程序中佔用較低的優先級。在/oauth/confirm_access端點中,您能夠期待AuthorizationRequest綁定到會話中,攜帶全部須要用戶查詢的數據(默認的實現是WhitelabelApprovalEndpoint這樣查找起始點複製)。/oauth/authorize您能夠從該請求中獲取全部數據,而後根據須要進行渲染,而後全部用戶須要執行的操做都是回覆有關批准或拒絕受權的信息。請求參數直接傳遞給您UserApprovalHandlerAuthorizationEndpoint因此您能夠隨便解釋數據。默認UserApprovalHandler取決於您是否已經提供了一個ApprovalStore在你的AuthorizationServerEndpointsConfigurer(在這種狀況下,它是一個ApprovalStoreUserApprovalHandler)或不(在這種狀況下,它是一個TokenStoreUserApprovalHandler)。標準審批處理程序接受如下內容:默認取決於您是否已經提供了一個在你的(在這種狀況下,它是一個)或不(在這種狀況下,它是一個)。標準審批處理程序接受如下內容:默認取決於您是否已經提供了一個在你的(在這種狀況下,它是一個)或不(在這種狀況下,它是一個)。標準審批處理程序接受如下內容:

  • TokenStoreUserApprovalHandler:簡單的是/否決定經過user_oauth_approval等於「真」或「假」。
  • ApprovalStoreUserApprovalHandler:一組scope.*參數鍵與「*」等於所請求的範圍。參數的值能夠是「true」或「approved」(若是用戶批准了受權),則該用戶被認爲已經拒絕了該範圍。若是批准了至少一個範圍,則贈款是成功的。

注意:不要忘記在您爲用戶呈現的表單中包含CSRF保護。默認狀況下,Spring Security正期待一個名爲「_csrf」的請求參數(它在請求屬性中提供值)。有關更多信息,請參閱Spring Security用戶指南,或查看whitelabel實現的指導。

執行SSL

普通HTTP對於測試是很好的,但受權服務器只能在生產中使用SSL。您能夠在安全容器或代理服務器後面運行應用程序,若是正確設置代理和容器(這與OAuth2無關),則應該能夠正常運行。您也可能但願使用Spring Security requiresChannel()限制來保護端點。對於/authorize端點,由您來作,做爲您正常應用程序安全性的一部分。對於/token端點AuthorizationServerEndpointsConfigurer,可使用該sslOnly()方法設置一個標誌。在這兩種狀況下,安全通道設置是可選的,可是若是Spring Security在不安全的通道上檢測到請求,則會致使Spring Security重定向到安全通道。

自定義錯誤處理

受權服務器中的錯誤處理使用標準Spring MVC功能,即@ExceptionHandler端點自己的方法。用戶還能夠向WebResponseExceptionTranslator端點自身提供這些改變響應內容的最佳方式,而不是渲染方式。在受權HttpMesssageConverters端點的狀況下,在令牌端點和OAuth錯誤視圖(/oauth/error)的狀況下,異常呈現(能夠添加到MVC配置中)。該白色標籤錯誤的端點提供了HTML的響應,但用戶可能須要提供自定義實現(如只需添加一個@Controller@RequestMapping("/oauth/error"))。

將用戶角色映射到範圍

限制令牌範圍不只僅是分配給客戶端的範圍,還能夠根據用戶本身的權限來進行限制。若是您在其中使用DefaultOAuth2RequestFactoryAuthorizationEndpoint則能夠設置一個標誌checkUserScopes=true,以將容許的範圍限制爲僅與那些與用戶角色匹配的範圍。你也能夠注入OAuth2RequestFactoryTokenEndpoint但只有工做(即密碼受權),若是你也安裝一個TokenEndpointAuthenticationFilter- 你只須要在HTTP以後添加該過濾器BasicAuthenticationFilter。固然,您還能夠實現本身的規則,將做用域映射到角色並安裝本身的版本OAuth2RequestFactory。將AuthorizationServerEndpointsConfigurer讓你注入一個定製的OAuth2RequestFactory,因此你可使用該功能來創建一個工廠,若是你使用@EnableAuthorizationServer

資源服務器配置

資源服務器(能夠與受權服務器或單獨的應用程序相同)提供受OAuth2令牌保護的資源。Spring OAuth提供了實現此保護的Spring Security認證過濾器。您能夠@EnableResourceServer@Configuration類上打開它,並使用a進行配置(必要時)ResourceServerConfigurer。能夠配置如下功能:

  • tokenServices:定義令牌服務的bean(實例ResourceServerTokenServices)。
  • resourceId:資源的ID(可選,但建議並由驗證服務器驗證,若是存在)。
  • 其餘擴展點(例如tokenExtractor從傳入請求中提取令牌)
  • 請求匹配的受保護資源(默認爲所有)
  • 受保護資源的訪問規則(默認爲「已驗證」)
  • HttpSecuritySpring Security中配置程序容許的受保護資源的其餘自定義

@EnableResourceServer註釋添加類型的過濾器OAuth2AuthenticationProcessingFilter自動Spring Security的過濾器鏈。

在XML中有一個<resource-server/>帶有id屬性的元素- 這是一個servlet的bean ID,Filter而後能夠手動添加到標準的Spring Security鏈。

ResourceServerTokenServices是與受權服務器的合同的另外一半。若是資源服務器和受權服務器在同一個應用程序中,而後使用,DefaultTokenServices那麼您不須要太費心思考,由於它實現了全部必要的接口,所以它自動一致。若是您的資源服務器是一個單獨的應用程序,那麼您必須確保與受權服務器的功能相匹配,並提供一個ResourceServerTokenServices正確的解碼令牌。與受權服務器同樣,您常常可使用該DefaultTokenServices選項,而且選擇主要經過TokenStore(後端存儲或本地編碼)來表達。RemoteTokenServices一個替代方案是Spring OAuth功能(不是規範的一部分),容許資源服務器經過受權服務器(/oauth/check_token)上的HTTP資源解碼令牌。RemoteTokenServices若是資源服務器中沒有大量的流量(每一個請求都必須與受權服務器進行驗證),或者若是可以緩存結果,那麼它們是方便的。要使用/oauth/check_token端點,您須要經過更改其訪問規則(默認爲「denyAll()」)來公開它AuthorizationServerSecurityConfigurer,例如

@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端點(因此信任的資源能夠得到JWT驗證的公鑰)。這兩個端點受到使用客戶端憑據的HTTP基自己份驗證的保護。

配置OAuth感知表達式處理程序

您可能但願利用Spring Security 基於表達式的訪問控制。表達式處理程序將默認在@EnableResourceServer安裝程序中註冊。這些表達式包括*#oauth2.clientHasRole*,#oauth2.clientHasAnyRole和*#oath2.denyClient*,可用於根據oauth客戶端的角色提供訪問(請參閱OAuth2SecurityExpressionMethods全面的列表)。在XML中,您能夠expression-handler使用常規<http/>安全配置的元素註冊一個oauth感知表達式處理程序。

OAuth 2.0客戶端

OAuth 2.0客戶端機制負責訪問其餘服務器的OAuth 2.0保護資源。該配置包括創建用戶可能訪問的相關受保護資源。客戶端還可能須要提供用於存儲用戶的受權碼和訪問令牌的機制。

受保護的資源配置

受保護的資源(或「遠程資源」)可使用類型的bean定義來定義OAuth2ProtectedResourceDetails。受保護的資源具備如下屬性:

  • id:資源的id。該id僅由客戶端用於查找資源; 它在OAuth協議中從未使用過。它也被用做bean的id。
  • clientId:OAuth客戶端ID。這是OAuth提供商識別您的客戶端的ID。
  • clientSecret:與資源相關的祕密。默認狀況下,沒有密碼爲空。
  • accessTokenUri:提供訪問令牌的提供者OAuth端點的URI。
  • scope:逗號分隔的字符串列表,指定對資源的訪問範圍。默認狀況下,不指定範圍。
  • clientAuthenticationScheme:您的客戶端用於向訪問令牌端點進行身份驗證的方案。建議的值:「http_basic」和「form」。默認值爲「http_basic」。請參閱OAuth 2規範的第2.1節。

不一樣的受權類型具備不一樣的具體實現OAuth2ProtectedResourceDetails(例如ClientCredentialsResource,對於「client_credentials」受權類型)。對於須要用戶受權的受權類型,還有一個其餘屬性:

  • userAuthorizationUri:若是用戶須要受權訪問資源,則用戶將被重定向到的uri。請注意,這並不老是須要,具體取決於支持哪一個OAuth 2配置文件。

在XML中有一個<resource/>能夠用來建立類型的bean的元素OAuth2ProtectedResourceDetails。它具備匹配上述全部屬性的屬性。

客戶端配置

對於OAuth 2.0客戶端,使用簡化配置@EnableOAuth2Client。這有兩件事情:

  • 建立一個過濾器bean(帶有ID oauth2ClientContextFilter)來存儲當前的請求和上下文。在須要在請求期間進行身份驗證的狀況下,管理重定向到和從OAuth認證uri。
  • AccessTokenRequest在請求範圍中建立一個類型的bean 。受權代碼(或隱式)受權客戶端可使用這種方式來保持與個別用戶的狀態相關。

過濾器必須鏈接到應用程序中(例如,使用 同一名稱的Servlet初始化程序或web.xml配置DelegatingFilterProxy)。

AccessTokenRequest能夠在使用 OAuth2RestTemplate這樣的:

@Autowired
private OAuth2ClientContext oauth2Context;

@Bean
public OAuth2RestTemplate sparklrRestTemplate() {
	return new OAuth2RestTemplate(sparklr(), oauth2Context);
}
複製代碼

在會話範圍中放置OAuth2ClientContext(爲您),以保持不一樣用戶的狀態分開。沒有了,您將不得不本身在服務器上管理等效的數據結構,將傳入的請求映射到用戶,並將每一個用戶與單獨的實例相關聯OAuth2ClientContext

在XML中有一個<client/>帶有id屬性的元素- 這是一個servlet的bean id,Filter在這種@Configuration狀況下必須映射爲一個DelegatingFilterProxy(具備相同名稱)。

訪問受保護的資源

一旦您提供了資源的全部配置,您如今能夠訪問這些資源。用於訪問這些資源的建議的方法是經過使用所述RestTemplate在彈簧3引入。Spring Security的OAuth提供只須要提供一個實例的RestTemplate的擴展OAuth2ProtectedResourceDetails。要使用用戶令牌(受權代碼受權),您應該考慮使用建立一些請求和會話做用域上下文對象的@EnableOAuth2Client配置(或XML等效項<oauth:rest-template/>),以便不一樣用戶的請求在運行時不會相沖突。

做爲通常規則,Web應用程序不該使用密碼受權,所以ResourceOwnerPasswordResourceDetails若是能夠支持,請避免使用AuthorizationCodeResourceDetails。若是您很是須要從Java客戶端工做的密碼受權,則使用相同的機制來配置您的憑據,並將憑據OAuth2RestTemplate添加到AccessTokenRequest(這是一個Map短暫的),而不是ResourceOwnerPasswordResourceDetails(在全部訪問令牌之間共享)。

在客戶端中持久化令牌

客戶端並不須要堅持令牌,但它能夠很好的爲不要求用戶每次在客戶端應用程序從新啓動時批准新的代金券授予。該ClientTokenServices接口定義了所必需的持續的OAuth爲特定用戶2.0的令牌的動做。提供了一個JDBC實現,但若是您但願實現本身的服務來將持久性數據庫中的訪問令牌和關聯的身份驗證明例存儲起來,那麼您可使用。若是要使用此功能,您須要提供一個專門配置TokenProviderOAuth2RestTemplate

@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)不能正確地實現規範,或者他們只是堅持使用舊版本的規範,而不是Spring Security OAuth。要在客戶端應用程序中使用這些提供程序,您可能須要調整客戶端基礎架構的各個部分。

以Facebook爲例,應用程序中有一個Facebook功能tonr2(您須要更改配置以添加您本身的,有效的客戶端ID和密碼 - 它們很容易在Facebook網站上生成)。

Facebook令牌響應在令牌的到期時間(它們使用expires而不是expires_in)中也包含不符合規定的JSON條目,所以,若是要在應用程序中使用到期時間,則必須使用自定義手動解碼OAuth2SerializationService

相關文章
相關標籤/搜索