【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.html

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.java

这是OAuth2.0的用户指导,对于OAuth1.0,全部事情都是不一样的,请看其本身的指导文档git

这个用户指导文档分为两部分,第一部分是OAuth2.0的提供商,第二部分是OAuth2.0的客户端。对于提供商和客户端,最好的源码示例是整合测试app样例github

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).web

OAuth2.0提供商的机制是负责暴露OAuth2.0的保护资源。配置涉及创建能够独立或者表明用户访问受保护资源的OAuth2.0的客户端。供应商经过管理和验证访问受保护资源的OAuth2.0令牌来作到这些。在适当的状况下,提供者还必须为用户提供一个接口,以确承认以被授予对被保护资源的访问权。spring

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:sql

  • 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.express

在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解码。

相关文章
相关标签/搜索