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

相关文章
相关标签/搜索