【Spring Boot&& Spring Cloud系列】單點登錄SSO之OAuth2官方開發文檔翻譯


Introduction:介紹

This is the user guide for the support for OAuth 2.0. For OAuth 1.0, everything is different, so see its user guide.

This user guide is divided into two parts, the first for the OAuth 2.0 provider, the second for the OAuth 2.0 client. For both the provider and the client, the best source of sample code is the integration tests and sample apps.

這是OAuth2.0的用戶指導,對於OAuth1.0,所有事情都是不同的,請看其自己的指導文檔

這個用戶指導文檔分為兩部分,第一部分是OAuth2.0的提供商,第二部分是OAuth2.0的客戶端。對於提供商和客戶端,最好的源碼示例是整合測試app樣例

OAuth 2.0 Provider:OAuth2.0提供商

The OAuth 2.0 provider mechanism is responsible for exposing OAuth 2.0 protected resources. The configuration involves establishing the OAuth 2.0 clients that can access its protected resources independently or on behalf of a user. The provider does this by managing and verifying the OAuth 2.0 tokens used to access the protected resources. Where applicable, the provider must also supply an interface for the user to confirm that a client can be granted access to the protected resources (i.e. a confirmation page).

OAuth2.0提供商的機制是負責暴露OAuth2.0的保護資源。配置涉及建立可以獨立或者代表用戶訪問受保護資源的OAuth2.0的客戶端。供應商通過管理和驗證訪問受保護資源的OAuth2.0令牌來做到這些。在適當的情況下,提供者還必須為用戶提供一個接口,以確認可以被授予對被保護資源的訪問權。

OAuth 2.0 Provider Implementation:OAuth2.0提供者安裝

The provider role in OAuth 2.0 is actually split between Authorization Service and Resource Service, and while these sometimes reside in the same application, with Spring Security OAuth you have the option to split them across two applications, and also to have multiple Resource Services that share an Authorization Service. The requests for the tokens are handled by Spring MVC controller endpoints, and access to protected resources is handled by standard Spring Security request filters. The following endpoints are required in the Spring Security filter chain in order to implement OAuth 2.0 Authorization Server:

  • AuthorizationEndpoint is used to service requests for authorization. Default URL: /oauth/authorize.
  • TokenEndpoint is used to service requests for access tokens. Default URL: /oauth/token.

The following filter is required to implement an OAuth 2.0 Resource Server:

For all the OAuth 2.0 provider features, configuration is simplified using special Spring OAuth @Configuration adapters. There is also an XML namespace for OAuth configuration, and the schema resides at http://www.springframework.org/schema/security/spring-security-oauth2.xsd. The namespace is http://www.springframework.org/schema/security/oauth2.

在OAuth2中提供者的作用實際上是區分授權服務和資源服務,而這些服務有時駐留在相同的應用程序,使用Spring Security OAuth你可以選擇切分到兩個應用程序,同樣也可以選擇多個資源服務分享一個授權服務。令牌的請求由SpringMVC控制器切點處理,對受保護資源的訪問由標准的Spring Security過濾器處理。為了實現OAuth2授權服務器,需要在Spring Security過濾器鏈中實現如下的切點:

  • AuthorizationEndpoint是用於授權服務請求:默認的URL:/oauth/authorize.
  • TokenEndpoint是用於訪問令牌服務請求。默認的URL是:/oauth/token

 實現OAuth2資源服務器需要如下的過濾器:

 OAuth2AuthenticationProcessingFilter用來給一個有授權access token的請求加載授權信息。

對於所有OAuth2.0提供者的特性,配置是使用特殊的Spring OAuth @Configuration適配器簡化。對於OAuth配置同樣有XML命名空間,schema的地址在 http://www.springframework.org/schema/security/spring-security-oauth2.xsd 命令空間時http://www.springframework.org/schema/security/oauth2.

Authorization Server Configuration:授權服務配置

As you configure the Authorization Server, you have to consider the grant type that the client is to use to obtain an access token from the end-user (e.g. authorization code, user credentials, refresh token). The configuration of the server is used to provide implementations of the client details service and token services and to enable or disable certain aspects of the mechanism globally. Note, however, that each client can be configured specifically with permissions to be able to use certain authorization mechanisms and access grants. I.e. just because your provider is configured to support the "client credentials" grant type, doesn't mean that a specific client is authorized to use that grant type.

The @EnableAuthorizationServer annotation is used to configure the OAuth 2.0 Authorization Server mechanism, together with any @Beans that implement AuthorizationServerConfigurer (there is a handy adapter implementation with empty methods). The following features are delegated to separate configurers that are created by Spring and passed into the AuthorizationServerConfigurer:

  • ClientDetailsServiceConfigurer: a configurer that defines the client details service. Client details can be initialized, or you can just refer to an existing store.
  • AuthorizationServerSecurityConfigurer: defines the security constraints on the token endpoint.
  • AuthorizationServerEndpointsConfigurer: defines the authorization and token endpoints and the token services.

An important aspect of the provider configuration is the way that an authorization code is supplied to an OAuth client (in the authorization code grant). A authorization code is obtained by the OAuth client by directing the end-user to an authorization page where the user can enter her credentials, resulting in a redirection from the provider authorization server back to the OAuth client with the authorization code. Examples of this are elaborated in the OAuth 2 specification.

In XML there is an <authorization-server/> element that is used in a similar way to configure the OAuth 2.0 Authorization Server.

當配置授權服務的時候,必須考慮客戶端使用的授權類型以便於從終端用戶獲得訪問令牌.(比如:授權碼、用戶認證、刷新令牌)。服務器的配置是用於提供客戶端細節服務和令牌服務的實現,並在全局范圍內啟用或禁用某些機制。但是請注意,每個客戶端都可以配置為特定的權限,以便能夠使用某些授權機制和訪問授權。也就是說,僅僅由於提供者被配置為支持“客戶端憑據”授權類型,並不意味着特定客戶機被授權使用該授予類型。

@EnableAuthorizationServer注解連同任何實現了AuthorizationServerConfigurer(有一個方便的適配器實現,方法是空的)的@Bean來配置OAuth2授權服務器機制。以下的特征是委托獨立的有Spring創建並傳遞到AuthorizationServerConfigurer的配置:

  • ClientDetailsServiceConfigurer:定義客戶細節服務的配置,可以初始化客戶端細節,也可以引用現有的存儲。
  • AuthorizationServerSecurityConfigurer:定義了token切點的安全限制。AuthorizationServerEndpointsConfigurer:定義了授權。令牌切點和令牌服務。


提供者配置的一個重要方面是提供授權碼給OAuth客戶端的方式。一個授權碼是通過AOuth客戶端引導頁面,用戶可以輸入自己的憑據,使得授權碼提供方返回授權碼到授權客戶端。這方面的例子闡述了OAuth的2規范。

在XML中是一個<authorization-server/>元素,與配置OAuth2.0是同樣的方式

Configuring Client Details:配置客戶端

The ClientDetailsServiceConfigurer (a callback from your AuthorizationServerConfigurer) can be used to define an in-memory or JDBC implementation of the client details service. Important attributes of a client are

  • clientId: (required) the client id.
  • secret: (required for trusted clients) the client secret, if any.
  • scope: The scope to which the client is limited. If scope is undefined or empty (the default) the client is not limited by scope.
  • authorizedGrantTypes: Grant types that are authorized for the client to use. Default value is empty.
  • authorities: Authorities that are granted to the client (regular Spring Security authorities).

Client details can be updated in a running application by access the underlying store directly (e.g. database tables in the case of JdbcClientDetailsService) or through the ClientDetailsManager interface (which both implementations of ClientDetailsService also implement).

NOTE: the schema for the JDBC service is not packaged with the library (because there are too many variations you might like to use in practice), but there is an example you can start from in the test code in github.

ClientDetailsServiceConfigurer(從AuthorizationServerConfigurer的一個回調)可以用來定義一個客戶端內存或JDBC實現細節服務。客戶端的重要屬性包括:

  • clientId: (必須的) 客戶端標識.
  • secret: (授信的客戶端是必須的) 如果有的話,客戶端的秘鑰.
  • scope:客戶端受限的范圍。 如果范圍未定義或者是空的(默認情況下)客戶端將不受范圍限制。
  • authorizedGrantTypes: 授權客戶端使用的授權類型。默認值是空的。
  • authorities: 授予客戶的權限 (合格的Spring Security 權限).

可以通過直接訪問底層存儲(比如:JdbcClientDetailsService中的數據表)或者ClientDetailsManager接口為正在運行的應用程序中更新客戶端詳細信息。

注意:對於JDBC服務的schema沒有打包到library中(因為在實踐中可能會有太多的變化)。但是這里有一個你可以開始使用的例子test code in github.

Managing Tokens:管理令牌

The AuthorizationServerTokenServices interface defines the operations that are necessary to manage OAuth 2.0 tokens. Note the following:

  • When an access token is created, the authentication must be stored so that resources accepting the access token can reference it later.
  • The access token is used to load the authentication that was used to authorize its creation.

When creating your AuthorizationServerTokenServices implementation, you may want to consider using the DefaultTokenServices which has many strategies that can be plugged in to change the format and storage of access tokens. By default it creates tokens via random value and handles everything except for the persistence of the tokens which it delegates to a TokenStore. The default store is an in-memory implementation, but there are some other implementations available. Here's a description with some discussion of each of them

  • The default InMemoryTokenStore is perfectly fine for a single server (i.e. low traffic and no hot swap to a backup server in the case of failure). Most projects can start here, and maybe operate this way in development mode, to make it easy to start a server with no dependencies.

  • The JdbcTokenStore is the JDBC version of the same thing, which stores token data in a relational database. Use the JDBC version if you can share a database between servers, either scaled up instances of the same server if there is only one, or the Authorization and Resources Servers if there are multiple components. To use the JdbcTokenStore you need "spring-jdbc" on the classpath.

  • The JSON Web Token (JWT) version of the store encodes all the data about the grant into the token itself (so no back end store at all which is a significant advantage). One disadvantage is that you can't easily revoke an access token, so they normally are granted with short expiry and the revocation is handled at the refresh token. Another disadvantage is that the tokens can get quite large if you are storing a lot of user credential information in them. The JwtTokenStore is not really a "store" in the sense that it doesn't persist any data, but it plays the same role of translating betweeen token values and authentication information in the DefaultTokenServices.

NOTE: the schema for the JDBC service is not packaged with the library (because there are too many variations you might like to use in practice), but there is an example you can start from in the test code in github. Be sure to @EnableTransactionManagement to prevent clashes between client apps competing for the same rows when tokens are created. Note also that the sample schema has explicit PRIMARY KEY declarations - these are also necessary in a concurrent environment.

AuthorizationServerTokenServices 接口定義了管理OAuth2.0令牌的必要操作。注意以下幾點:

  • 當創建訪問令牌時,必須存儲身份驗證,以便接受訪問令牌的資源稍后可以引用它。
  • 訪問令牌用於加載用於授權其創建的身份驗證。

當創建你的AuthorizationServerTokenServices實現時,你可能想考慮使用DefaultTokenServices它有許多策略可以插入到改變訪問令牌的格式和存儲中。  默認情況下,它創建令牌通過隨機數字和處理除了持久化令牌的所有事情,持久化令牌代表了一個TokenStore。默認存儲是內存中實現 in-memory implementation,但還有一些其他實現可用。這里有一個討論其中的每一個實現方式的描述:

  • 默認的InMemoryStore對於單個服務來說是很好的(例如:在失敗的情況下,低流量和沒有熱交換到備份服務器)。大多數項目可以從這里開始,也可能在開發模式下這樣操作,以簡化沒有依賴的服務器啟動。

  • JdbcTokenStore是做相同事情的 JDBC version版本,它保存令牌數據在一個關系型數據庫中. 如果可以在服務器之間共享數據庫,那么可以使用JDBC版本,如果只有一個服務器的實例,或者在有多個組件的授權和資源服務器上,也可以使用相同的服務器。想使用JdbcTokenStore的話需要在路徑中加入“spring-jdbc”.

  • JSON Web令牌(JWT)的存儲版本編碼所有的關於令牌本身的授權 (沒有后端存儲這是一個重要的優勢). 一個缺點是不能輕易撤銷訪問令牌,因此它們通常被授予較短的到期時間,並在刷新令牌中處理撤銷。另一個缺點是,如果您在其中存儲了大量的用戶憑據信息,令牌可能會變得相當大。JwtTokenStore不是一個真正意義上的持久化數據的“商店”,但是它在DefaultTokenServices中起着相同的翻譯令牌值和授權信息的作用。

注意: JDBC服務的schema沒有打包到library中(因為在實際中有太多的可供選擇)但是這里有一個你可以開始的例子test code in github. 確保使用 @EnableTransactionManagement去防止沖突的客戶端應用程序競爭相同的行當令牌創建。還要注意,示例schema有明確的主鍵聲明——這些在並發環境中也是必需的

JWT Tokens:JWT令牌

To use JWT tokens you need a JwtTokenStore in your Authorization Server. The Resource Server also needs to be able to decode the tokens so the JwtTokenStore has a dependency on a JwtAccessTokenConverter, and the same implementation is needed by both the Authorization Server and the Resource Server. The tokens are signed by default, and the Resource Server also has to be able to verify the signature, so it either needs the same symmetric (signing) key as the Authorization Server (shared secret, or symmetric key), or it needs the public key (verifier key) that matches the private key (signing key) in the Authorization Server (public-private or asymmetric key). The public key (if available) is exposed by the Authorization Server on the /oauth/token_key endpoint, which is secure by default with access rule "denyAll()". You can open it up by injecting a standard SpEL expression into the AuthorizationServerSecurityConfigurer (e.g. "permitAll()" is probably adequate since it is a public key).

To use the JwtTokenStore you need "spring-security-jwt" on your classpath (you can find it in the same github repository as Spring OAuth but with a different release cycle).

想使用JWT令牌的話在你的授權服務器中需要一個JwtTokenStore.資源服務器也需要能夠解碼令牌,所以JwtTokenStore對於JwtAccessTokenConverter有依賴,授權服務器和資源服務器也同樣需要相同的實現.令牌簽名的默認情況下,服務器的資源也必須能夠驗證簽名,所以他需要授權服務器的相同的對稱秘鑰,也需要與授權服務器中私鑰相對應的公鑰。公鑰,如果有的話通過/osuth/token_key切點暴露,這是默認的安全訪問規則”denyall()”。你可以通過在AuthorizationServerSecurityConfigurer切入一個表達式打開它(“permitall()”可能是適當的因為它是一個公共密鑰)。

如果想使用JwtTokenStore的話你需要加入“spring-security-jwt”到類路徑中(你可以在同一個GitHub庫Spring OAuth但不同的發布版本中找到它)。

Grant Types:授權類型

The grant types supported by the AuthorizationEndpoint can be configured via the AuthorizationServerEndpointsConfigurer. By default all grant types are supported except password (see below for details of how to switch it on). The following properties affect grant types:

  • authenticationManager: password grants are switched on by injecting an AuthenticationManager.
  • userDetailsService: if you inject a UserDetailsService or if one is configured globally anyway (e.g. in a GlobalAuthenticationManagerConfigurer) then a refresh token grant will contain a check on the user details, to ensure that the account is still active
  • authorizationCodeServices: defines the authorization code services (instance of AuthorizationCodeServices) for the auth code grant.
  • implicitGrantService: manages state during the imlpicit grant.
  • tokenGranter: the TokenGranter (taking full control of the granting and ignoring the other properties above)

In XML grant types are included as child elements of the authorization-server.

AuthorizationEndpoint支持的授權類型可以通過AuthorizationServerEndpointsConfigurer配置。默認情況下除了密碼之外的所有授權類型都是支持的(有關如何切換的詳細信息,請參見下文)。下列屬性影響授予類型:

  • authenticationManager: 通過注入AuthenticationManager開啟密碼授權。
  • userDetailsService:如果你注入一個UserDetailsService或者配置全局訪問(GlobalAuthenticationManagerConfigurer),然后刷新令牌授權將包含對用戶詳細信息的檢查,以確保賬戶仍然處於活動狀態。
  • authorizationCodeServices:為認證代碼授權定義授權碼服務(例如AuthorizationCodeServices)。
  • implicitGrantService: 非法授權中管理狀態
  • tokenGranter: the TokenGranter (完全控制授予和忽略上述的其他屬性)

Configuring the Endpoint URLs:配置切點URLs

The AuthorizationServerEndpointsConfigurer has a pathMapping() method. It takes two arguments:

  • The default (framework implementation) URL path for the endpoint
  • The custom path required (starting with a "/")

The URL paths provided by the framework are /oauth/authorize (the authorization endpoint), /oauth/token (the token endpoint), /oauth/confirm_access (user posts approval for grants here), /oauth/error (used to render errors in the authorization server), /oauth/check_token (used by Resource Servers to decode access tokens), and /oauth/token_key (exposes public key for token verification if using JWT tokens).

N.B. the Authorization endpoint /oauth/authorize (or its mapped alternative) should be protected using Spring Security so that it is only accessible to authenticated users. For instance using a standard 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
    }

Note: if your Authorization Server is also a Resource Server then there is another security filter chain with lower priority controlling the API resources. Fo those requests to be protected by access tokens you need their paths not to be matched by the ones in the main user-facing filter chain, so be sure to include a request matcher that picks out only non-API resources in the WebSecurityConfigurer above.

The token endpoint is protected for you by default by Spring OAuth in the @Configuration support using HTTP Basic authentication of the client secret. This is not the case in XML (so it should be protected explicitly).

In XML the <authorization-server/> element has some attributes that can be used to change the default endpoint URLs in a similar way. The /check_token endpoint has to be explicitly enabled (with the check-token-enabled attribute).

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資源。對於那些被訪問令牌保護的請求你需要他們的路徑不被過濾器鏈過濾,所以確保包含一個請求匹配在WebSecurityConfigureshang上剔除。

默認情況下令牌切點通過使用@Configuration支持的Spring OAuth的HTTP的基本授權客戶端秘鑰保護你。在XML中不是這樣的(因此他應該顯示地保護他)。

在XML中的<authorization-server/>元素中有一些屬性可以用來以默認的方式去改變默認切點的URL路徑。/check_token切點必須顯式啟用(使用check-token-enable屬性)。

Customizing the UI:定制化UI

Most of the Authorization Server endpoints are used primarily by machines, but there are a couple of resource that need a UI and those are the GET for /oauth/confirm_access and the HTML response from /oauth/error. They are provided using whitelabel implementations in the framework, so most real-world instances of the Authorization Server will want to provide their own so they can control the styling and content. All you need to do is provide a Spring MVC controller with @RequestMappings for those endpoints, and the framework defaults will take a lower priority in the dispatcher. In the /oauth/confirm_access endpoint you can expect an AuthorizationRequest bound to the session carrying all the data needed to seek approval from the user (the default implementation is WhitelabelApprovalEndpoint so look there for a starting point to copy). You can grab all the data from that request and render it however you like, and then all the user needs to do is POST back to /oauth/authorize with information about approving or denying the grant. The request parameters are passed directly to a UserApprovalHandler in the AuthorizationEndpoint so you can interpret the data more or less as you please. The default UserApprovalHandler depends on whether or not you have supplied an ApprovalStore in your AuthorizationServerEndpointsConfigurer (in which case it is an ApprovalStoreUserApprovalHandler) or not (in which case it is a TokenStoreUserApprovalHandler). The standard approval handlers accept the following:

  • TokenStoreUserApprovalHandler: a simple yes/no decision via user_oauth_approval equals to "true" or "false".

  • ApprovalStoreUserApprovalHandler: a set of scope.* parameter keys with "*" equal to the scopes being requested. The value of the parameter can be "true" or "approved" (if the user approved the grant) else the user is deemed to have rejected that scope. A grant is successful if at least one scope is approved.

NOTE: don't forget to include CSRF protection in your form that you render for the user. Spring Security is expecting a request parameter called "_csrf" by default (and it provides the value in a request attribute). See the Spring Security user guide for more information on that, or look at the whitelabel implementation for guidance.

大多數的授權服務器終端主要由機器的使用,但是一些資源,需要一個UI和那些去獲得/oauth/confirm_access的響應和/oauth/error的HTML響應。框架中他們提供 白標簽實現,因此真實環境中的授權服務器將提供他們自己的頁面以便於他們控制樣式和內容。你所需要做的就是為這些切點提供一個Spring MVC控制器的映射,框架默認的分發將降低優先級。在/oauth/confirm_access切點中你需要使用一個AuthorizationRequest去綁定會話所攜帶的所有必要的數據用於向用戶尋求批准(默認的實現方式是WhitelabelApprovalEndpoint,所以看這里復制用於開始)。你可以從請求中抓取所有的數據並以你喜歡的方式去渲染它,用戶需要做的就是發送關於同意或者拒絕授權的/oauth/authorize信息。請求參數在AuthorizationEndpoint中直接傳遞給UserApprovalHandler,所以你可以隨意的決定解析數據的多少。默認的UserApprovalHandler取決於你是否在你的AuthorizationServerEndpointConfirurer(在這種情況下它是一個TokenStoreUserApprovalHandler)中提供一個ApprovalStore.標准的同意處理接收如下:

  • TokenStoreUserApprovalHandler:通過user_oauth_approval的一個簡單的yes/no相當於true或false

  • ApprovalStoreUserApprovalHandler: 一系列的scope.*參數值使用*代表與請求的范圍相同。參數的值可以是true或approved(如果用戶同意授權的話)負責的話被認為用戶拒絕該范圍。至少有一個范圍被同意的話視為授權是成功的。

注意:不用忘記為你想用戶渲染的使用CSRF保護。默認情況下Spring Security需要一個名為"_csrf"的參數(它提供了請求屬性的值)。查看Spring Security的用戶知道獲得更多的信息,或者查看whitelabel實施指導。

Enforcing SSL:強制SSL

Plain HTTP is fine for testing but an Authorization Server should only be used over SSL in production. You can run the app in a secure container or behind a proxy and it should work fine if you set the proxy and the container up correctly (which is nothing to do with OAuth2). You might also want to secure the endpoints using Spring Security requiresChannel() constraints. For the /authorize endpoint is up to you to do that as part of your normal application security. For the /token endpoint there is a flag in the AuthorizationServerEndpointsConfigurer that you can set using the sslOnly() method. In both cases the secure channel setting is optional but will cause Spring Security to redirect to what it thinks is a secure channel if it detects a request on an insecure channel.

在測試環境中可以使用HTTP但是在生產環境中應該只能使用SSL。如果你把代理和容器設置正確的話(這與OAuth2沒有任何關系),可以在一個安全的容器或者代理中運行應用程序。你可能同樣想使用Spring Security的requiresChannel()約束保護切點。對於/authorize切點來說你可以按照正常的應用程序安全的一部分來完成。對於/token切點來說在AuthorizationServerEndpointsConfigurer中有一個標識你可以使用sslOnly()方法。在這兩種情況下,安全通道的設置都是可選的,但是如果檢測到不安全通道上的請求時將導致Spring Security重定向到它認為是安全通道的位置。

Customizing the Error Handling:個性化錯誤處理

Error handling in an Authorization Server uses standard Spring MVC features, namely @ExceptionHandler methods in the endpoints themselves. Users can also provide a WebResponseExceptionTranslator to the endpoints themselves which is the best way to change the content of the responses as opposed to the way they are rendered. The rendering of exceptions delegates to HttpMesssageConverters (which can be added to the MVC configuration) in the case of token endpoint and to the OAuth error view (/oauth/error) in the case of teh authorization endpoint. The whitelabel error endpoint is provided for HTML responses, but users probably need to provide a custom implementation (e.g. just add a @Controllerwith @RequestMapping("/oauth/error")).

在授權服務器中使用標准的SpringMVC特性處理錯誤,也就是切點本身的@ExceptionHandler.用戶還可以為切點本身提供WebResponseExceptionTranslator,這個切點本身是改變回應的內容而不是呈現的方式的最好的方法。就令牌切點和Oauth錯誤視圖(/oauth/error)和授權切點來說錯誤渲染由HttpMessageConverters(可以加入MVC配置)代理。whitelabel錯誤切點是為HTML響應提供的,但是用戶可能需要提供一個個性化實現(比如,只是添加一個有@RequestMapping("/oauth/error")的@Controller)。

Mapping User Roles to Scopes:映射用戶角色到授權范圍

It is sometimes useful to limit the scope of tokens not only by the scopes assigned to the client, but also according to the user's own permissions. If you use a DefaultOAuth2RequestFactory in your AuthorizationEndpoint you can set a flag checkUserScopes=true to restrict permitted scopes to only those that match the user's roles. You can also inject an OAuth2RequestFactory into the TokenEndpoint but that only works (i.e. with password grants) if you also install a TokenEndpointAuthenticationFilter - you just need to add that filter after the HTTP BasicAuthenticationFilter. Of course, you can also implement your own rules for mapping scopes to roles and install your own version of the OAuth2RequestFactory. The AuthorizationServerEndpointsConfigurer allows you to inject a custom OAuth2RequestFactory so you can use that feature to set up a factory if you use @EnableAuthorizationServer.

有時候不僅可以通過分配給客戶機的范圍來限制令牌的范圍,也可以根據用戶自己的權限來限制令牌的范圍。如果你的AuthorizationEndpoint切點中使用了DefaultOAuth2RequestFactory你可以設置checkUserScopes=true來限制匹配角色的用戶范圍。你也可以在TokenEndpoint中注入OAuth2RequestFatory但是它只有在安裝的TokenEndpointAuthenticatiobFilter--你只需要在HTTP BasicAuthenticationFilter后加入此過濾器,的時候才能使用。當然,你也可以實現自己的映射角色范圍的規則和安裝你自己版本的OAuth2RequestFactory。AuthorizationServerEndpointConfigure允許你注入一個定制化的OAuth2RequestFactory,所以如果你使用@EnableAuthorizationServer的話你可以使用這些特性去設置OAuth2RequestFactory.

Resource Server Configuration:資源服務器的配置

A Resource Server (can be the same as the Authorization Server or a separate application) serves resources that are protected by the OAuth2 token. Spring OAuth provides a Spring Security authentication filter that implements this protection. You can switch it on with @EnableResourceServer on an @Configuration class, and configure it (as necessary) using a ResourceServerConfigurer. The following features can be configured:

  • tokenServices: the bean that defines the token services (instance of ResourceServerTokenServices).
  • resourceId: the id for the resource (optional, but recommended and will be validated by the auth server if present).
  • other extension points for the resourecs server (e.g. tokenExtractor for extracting the tokens from incoming requests)
  • request matchers for protected resources (defaults to all)
  • access rules for protected resources (defaults to plain "authenticated")
  • other customizations for the protected resources permitted by the HttpSecurity configurer in Spring Security

The @EnableResourceServer annotation adds a filter of type OAuth2AuthenticationProcessingFilter automatically to the Spring Security filter chain.

In XML there is a <resource-server/> element with an id attribute - this is the bean id for a servlet Filter that can then be added manually to the standard Spring Security chain.

Your ResourceServerTokenServices is the other half of a contract with the Authorization Server. If the Resource Server and Authorization Server are in the same application and you use DefaultTokenServices then you don't have to think too hard about this because it implements all the necessary interfaces so it is automatically consistent. If your Resource Server is a separate application then you have to make sure you match the capabilities of the Authorization Server and provide a ResourceServerTokenServices that knows how to decode the tokens correctly. As with the Authorization Server, you can often use the DefaultTokenServices and the choices are mostly expressed through the TokenStore (backend storage or local encoding). An alternative is the RemoteTokenServices which is a Spring OAuth features (not part of the spec) allowing Resource Servers to decode tokens through an HTTP resource on the Authorization Server (/oauth/check_token). RemoteTokenServices are convenient if there is not a huge volume of traffic in the Resource Servers (every request has to be verified with the Authorization Server), or if you can afford to cache the results. To use the /oauth/check_token endpoint you need to expose it by changing its access rule (default is "denyAll()") in the AuthorizationServerSecurityConfigurer, e.g.

		@Override
		public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
			oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess(
					"hasAuthority('ROLE_TRUSTED_CLIENT')");
		}

In this example we are configuring both the /oauth/check_token endpoint and the /oauth/token_key endpoint (so trusted resources can obtain the public key for JWT verification). These two endpoints are protected by HTTP Basic authentication using client credentials.

資源服務器是由OAuth2令牌保護的資源服務。Spring OAuth提供了一個Spring Security授權過濾器來實現它的保護。你可以在一個@Configuration上使用@EnableResourceServer切換,並使用ResourceServerConfigurer配置它。可以配置如下的功能:

  • tokenServices: 定義令牌服務的Bean. (ResourceServerTokenServices的實例).
  • resourceId: 資源的id(可選的,如果存在的話將會被授權服務驗證。
  • 資源服務器的其他擴展選項(e.g. tokenExtractor從傳入請求中提取令牌)
  • 對受保護的資源請求的匹配(默認是所有)
  • 對保護資源的訪問規則 (默認為“已驗證”)
  • 在Spring Security中由HttpSecurity允許的自定義保護資源。

由@EnableResourceServer 聲明添加OAuth2AuthenticationProcessingFilter 的過濾器到Spring Security過濾器鏈。

在XML中由一個擁有id屬性的<resource-server/>元素--這是可以自動加入到標准Spring Security鏈中的過濾器的id.

Configuring An OAuth-Aware Expression Handler:配置一個OAuth-Aware表達式處理程序

You may want to take advantage of Spring Security's expression-based access control. An expression handler will be registered by default in the @EnableResourceServer setup. The expressions include #oauth2.clientHasRole, #oauth2.clientHasAnyRole, and #oath2.denyClient which can be used to provide access based on the role of the oauth client (see OAuth2SecurityExpressionMethods for a comprehensive list). In XML you can register a oauth-aware expression handler with the expression-handler element of the regular <http/> security configuration.

你可能想利用Spring Security的 expression-based access control.。表達式處理將會在@EnableResourceServer啟動的時候自動注冊。表達式包括#oauth2.clientHasRole,#oauth2.clientHasAnyRole和可以基於角色的權限客戶端提供訪問的#oauth2.denyClient(查看綜合列表的OAuth2SecurityExpressionMethods)。在XML中你可以使用普通的<http/>的安全配置的expression-handler元素注冊oauth-aware表達式

OAuth 2.0 Client:OAuth2.0客戶端

The OAuth 2.0 client mechanism is responsible for access the OAuth 2.0 protected resources of other servers. The configuration involves establishing the relevant protected resources to which users might have access. The client may also need to be supplied with mechanisms for storing authorization codes and access tokens for users.

OAuth2客戶端的機制是訪問其他服務器的受保護的資源。配置涉及建立用戶可以訪問的相關保護資源。客戶端可能還需要提供用於存儲用戶的授權代碼和訪問令牌的機制。

Protected Resource Configuration:保護資源配置

Protected resources (or "remote resources") can be defined using bean definitions of type OAuth2ProtectedResourceDetails. A protected resource has the following properties:

  • id: The id of the resource. The id is only used by the client to lookup the resource; it's never used in the OAuth protocol. It's also used as the id of the bean.
  • clientId: The OAuth client id. This is the id by which the OAuth provider identifies your client.
  • clientSecret: The secret associated with the resource. By default, no secret is empty.
  • accessTokenUri: The URI of the provider OAuth endpoint that provides the access token.
  • scope: Comma-separted list of strings specifying the scope of the access to the resource. By default, no scope will be specified.
  • clientAuthenticationScheme: The scheme used by your client to authenticate to the access token endpoint. Suggested values: "http_basic" and "form". Default: "http_basic". See section 2.1 of the OAuth 2 spec.

Different grant types have different concrete implementations of OAuth2ProtectedResourceDetails (e.g. ClientCredentialsResource for "client_credentials" grant type). For grant types that require user authorization there is a further property:

  • userAuthorizationUri: The uri to which the user will be redirected if the user is ever needed to authorize access to the resource. Note that this is not always required, depending on which OAuth 2 profiles are supported.

In XML there is a <resource/> element that can be used to create a bean of type OAuth2ProtectedResourceDetails. It has attributes matching all the properties above.

保護資源可以使用OAuth2ProtectedResourceDetails類型的Bean去定義。一個受保護的資源具有如下屬性:

  • id: 資源的id,這個id不能用於OAuth協議,僅僅是用客戶端使用去尋找資源。他同樣被用作Bean的id。
  • clientId: OAuth客戶端id,這是OAuth提供者授權給你的客戶端的id.
  • clientSecret: 與資源相關聯的資源。默認情況下沒有秘鑰是空的。
  • accessTokenUri: 供應商的提供訪問令牌的OAuth的切點的URL。
  • scope: 以逗號分隔的字符串指定的資源的訪問范圍列表。默認情況下,不會指定任何作用域。
  • clientAuthenticationScheme: 客戶端用來訪問令牌切點的schema.建議值是:“http_basic”和“form”。默認是:“http_basic”.查看OAuth2規范的2.1節。

不同的授權類型有不同的OAuth2ProtectedResourceDetails具體實現(比如:“client_credentials”授權類型的ClientCredentialsResource)。對於需要用戶授權的准許類型,還有一個屬性:

  • userAuthorizationUri: 如果用戶需要授權訪問資源,則用戶將重定向該URI,注意,這取決於支持哪一個OAuth2的規范並不總是必須的。

在XML中可以使用<resource/>元素創建一個OAuth2ProtectedResourceDetails類型的Bean.它有匹配上述所有特性的屬性。

Client Configuration:客戶端配置

For the OAuth 2.0 client, configuration is simplified using @EnableOAuth2Client. This does 2 things:

  • Creates a filter bean (with ID oauth2ClientContextFilter) to store the current request and context. In the case of needing to authenticate during a request it manages the redirection to and from the OAuth authentication uri.

  • Creates a bean of type AccessTokenRequest in request scope. This can be used by authorization code (or implicit) grant clients to keep state related to individual users from colliding.

The filter has to be wired into the application (e.g. using a Servlet initializer or web.xml configuration for a DelegatingFilterProxy with the same name).

The AccessTokenRequest can be used in an OAuth2RestTemplate like this:

@Autowired
private OAuth2ClientContext oauth2Context;

@Bean
public OAuth2RestTemplate sparklrRestTemplate() {
	return new OAuth2RestTemplate(sparklr(), oauth2Context);
}

The OAuth2ClientContext is placed (for you) in session scope to keep the state for different users separate. Without that you would have to manage the equivalent data structure yourself on the server, mapping incoming requests to users, and associating each user with a separate instance of the OAuth2ClientContext.

In XML there is a <client/> element with an id attribute - this is the bean id for a servlet Filter that must be mapped as in the @Configurationcase to a DelegatingFilterProxy (with the same name).

對於OAuth2客戶端,使用@EnableOAuth2Client簡化配置,需要做兩件事情:

  • 創建一個過濾器Bean(id為oauth2ClientContextFilter)去存儲當前請求和上下文。在請求需要授權的案例中,它管理了重定向到和來自OAuth授權的路徑。

  • 在請求上下文中創建一個AccessTokenRequest 的Bean.這可以通過授權代碼授權客戶端使用,以保持與單個用戶相關的狀態不會碰撞。

過濾器必須連接到應用程序中。(比如:使用Servlet初始化或者在web.xml文件中為DelegatingFilterProxy 配置相同的名字。

可以在OAuth2RestTemplate 以如下的方式使用AccessTokenRequest :

@Autowired
private OAuth2ClientContext oauth2Context;

@Bean
public OAuth2RestTemplate sparklrRestTemplate() {
	return new OAuth2RestTemplate(sparklr(), oauth2Context);
}

OAuth2ClientContext 放置在session范圍內以分別為不同的用戶保持狀態。 如果不這樣的話你需要在服務商自己管理同等的數據結構,映射用戶傳入的需求,並為每一個用過關聯單獨的OAuth2ClientContext實例。

在XML中有一個擁有id屬性的<client/>元素--這是過濾器的id,這個過濾器必須在@Configuration中映射到DelegatingFilterProxy(使用相同的名字).

Accessing Protected Resources:訪問受保護的資源

Once you've supplied all the configuration for the resources, you can now access those resources. The suggested method for accessing those resources is by using the RestTemplate introduced in Spring 3. OAuth for Spring Security has provided an extension of RestTemplate that only needs to be supplied an instance of OAuth2ProtectedResourceDetails. To use it with user-tokens (authorization code grants) you should consider using the @EnableOAuth2Client configuration (or the XML equivalent <oauth:rest-template/>) which creates some request and session scoped context objects so that requests for different users do not collide at runtime.

As a general rule, a web application should not use password grants, so avoid using ResourceOwnerPasswordResourceDetails if you can in favour of AuthorizationCodeResourceDetails. If you desparately need password grants to work from a Java client, then use the same mechanism to configure your OAuth2RestTemplate and add the credentials to the AccessTokenRequest (which is a Map and is ephemeral) not the ResourceOwnerPasswordResourceDetails (which is shared between all access tokens).

一旦你為資源提供了配置,你可以訪問這些資源。訪問資源推薦的方法是使用the RestTemplate introduced in Spring 3.Spring Security的OAuth提供了一個擴展的RestTemplatean extension of RestTemplate ,只需要提供一個OAuth2ProtectedResourceDetails實例。如果想使用用戶-令牌的話你應該考慮使用@EnableOAuth2Client(或者與XML等同的<oauth:rest-template/>)配置,針對不同的用戶同一時間不發生碰撞創建了一些請求和會話作用於上下文對象。

作為一般規則,一個Web應用不應該使用密碼授權,所以如果你可以使用AuthorizationCodeResourceDetails的話避免使用ResourceOwnerPasswordResourceDetails。如果你確實很需要為Java客戶端提供密碼授權,使用相同的機制去配置你的OAuth2RestTemplate和為AccessTokenRequest(是一個Map並且是短暫的)而不是ResourceOwnerPasswordResourceDetails(所有的訪問憑證共享)添加憑證。

Persisting Tokens in a Client:在客戶端中持久化令牌

A client does not need to persist tokens, but it can be nice for users to not be required to approve a new token grant every time the client app is restarted. The ClientTokenServices interface defines the operations that are necessary to persist OAuth 2.0 tokens for specific users. There is a JDBC implementation provided, but you can if you prefer implement your own service for storing the access tokens and associated authentication instances in a persistent database. If you want to use this feature you need provide a specially configured TokenProvider to the OAuth2RestTemplatee.g.

@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; }

客戶端不需要持久化令牌,但是在每次重新啟動客戶端應用程序時用戶不需要批准新的令牌授予會更改。ClientTokenServices 接口定義了為特定用戶持久化OAuth2.0令牌的操作。提供了JDBC實現,但是你也可以自己實現自己的服務以便於在數據庫中持久化存儲訪問令牌和相關的身份驗證實例。如果你想使用這個特性的話你需要為OAuth2RestTemplate提供一個TokenProvider.

@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; }

 

Customizations for Clients of External OAuth2 Providers:為客戶端定制化外部的OAuth2的供應商

Some external OAuth2 providers (e.g. Facebook) do not quite implement the specification correctly, or else they are just stuck on an older version of the spec than Spring Security OAuth. To use those providers in your client application you might need to adapt various parts of the client-side infrastructure.

To use Facebook as an example, there is a Facebook feature in the tonr2 application (you need to change the configuration to add your own, valid, client id and secret - they are easy to generate on the Facebook website).

Facebook token responses also contain a non-compliant JSON entry for the expiry time of the token (they use expires instead of expires_in), so if you want to use the expiry time in your application you will have to decode it manually using a custom OAuth2SerializationService.

一些外部的OAuth2的供應商不不正確執行規范,或者他們只是停留在舊版本的的Spring Security中,要在客戶端應用程序中使用這些提供者,你可能需要調整客戶端基本結構的各個部分。

以Facebook為例,在tonr2應用中有Facebook的特性。(你需要更改配置來添加自己的有效的客戶ID和秘鑰,他們可以很容易的在Facebook網站獲得)

Facebook的響應包含一個令牌過期時間的非標准化的JSON入口(他們使用expires而不是expires_in)。所以如果你想在你的應用中使用過期時間你需要手動的使用定制化的OAuth2SerializationService解碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM