您的位置:首页 > 编程语言 > Java开发

Spring Security OAuth 2开发者指南

2017-07-13 15:51 411 查看

介绍

这个用户指南支持
OAuth 2.0
。对于OAuth 1.0,一切都是不同的,所以去这里看它的用户指南

本用户指南分为两部分,第一部分为OAuth 2.0提供者,第二部分为OAuth 2.0客户端。对于提供商和客户端,示例代码的最佳来源是集成测试示例应用程序

OAuth 2.0提供商

OAuth 2.0提供者机制负责公开OAuth 2.0受保护的资源。配置包括建立可独立或代表用户访问其受保护资源的OAuth 2.0客户端。提供者通过管理和验证用于访问受保护资源的OAuth 2.0令牌来执行此操作。在适用情况下,提供商还必须为用户提供一个接口,以确认客户端可以被授权访问受保护资源(即确认页面)。

OAuth 2.0提供程序实现

OAuth 2.0中的提供者角色实际上是在授权服务和资源服务之间分割的,而有时它们位于同一个应用程序中,使用Spring Security OAuth,您可以选择在两个应用程序之间进行拆分,还可以使用多个资源服务共享授权服务。令牌的请求由Spring MVC控制器端点处理,对受保护资源的访问由标准的Spring Security请求过滤器处理。为了实现OAuth 2.0授权服务器,Spring Security过滤器链中需要以下端点:

AuthorizationEndpoint
用于服务请求授权。默认网址:
/oauth/authorize


TokenEndpoint
用于服务访问令牌的请求。默认网址:
/oauth/token


实施OAuth 2.0资源服务器需要以下过滤器:

OAuth2AuthenticationProcessingFilter
用于加载给定的认证访问令牌请求的认证。

对于所有OAuth 2.0提供程序功能,使用特殊的Spring OAuth
@Configuration
适配器简化了配置。还有一个用于OAuth配置的XML命名空间,并且模式位于http://www.springframework.org/schema/security/spring-security-oauth2.xsd。命名空间是
http://www.springframework.org/schema/security/oauth2


授权服务器配置

在配置授权服务器时,必须考虑客户端要从最终用户获取访问令牌(例如授权代码,用户凭据,刷新令牌)的授权类型。服务器的配置用于提供客户端详细信息服务和令牌服务的实现,并且能够全局启用或禁用机制的某些方面。但是,请注意,每个客户端都可以特别配置,以便能够使用某些授权机制和访问授权。也就是因为您的提供商配置为支持“客户端凭据”授权类型,并不意味着特定客户端被授权使用该授权类型。

@EnableAuthorizationServer
注释用于配置OAuth 2.0授权服务器机制,以及任何
@Beans
实现
AuthorizationServerConfigurer
(有一个方便的适配器实现与空的方法)。将以下功能委派给由Spring创建并传递到以下内容的单独配置程序
AuthorizationServerConfigurer


ClientDetailsServiceConfigurer
:定义客户端详细信息服务的配置程序。客户端的详细信息可以初始化,也可以参考现有的存储。

AuthorizationServerSecurityConfigurer
:定义令牌端点上的安全约束。

AuthorizationServerEndpointsConfigurer
:定义授权和令牌端点和令牌服务。

提供者配置的一个重要方面是将授权码提供给OAuth客户端(授权代码授权)的方式。授权代码由OAuth客户端通过将最终用户指向用户可以输入其凭据的授权页面获得,导致从提供商授权服务器重定向到具有授权码的OAuth客户端。这在OAuth 2规范中有详细阐述。

在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
可以插入的策略来更改访问令牌的格式和存储。默认情况下,它通过随机值创建令牌,并处理除了委托给a的令牌的持久性之外的所有内容
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
您可以从该请求中获取所有数据,然后根据需要进行渲染,然后所有用户需要执行的操作是回到有关批准或拒绝授权的信息。请求参数直接传递给您
UserApprovalHandler
AuthorizationEndpoint
所以您可以随便解释数据。默认
UserApprovalHandler
取决于您是否
ApprovalStore
AuthorizationServerEndpointsConfigurer
(在这种情况下是
ApprovalStoreUserApprovalHandler
)和(在这种情况下是一个
TokenStoreUserApprovalHandler
))中提供了一个。标准审批处理程序接受以下内容:默认取决于您是否在(在这种情况下是)和(在这种情况下是一个))中提供了一个。标准审批处理程序接受以下内容:默认取决于您是否在(在这种情况下是)和(在这种情况下是一个))中提供了一个。标准审批处理程序接受以下内容:

TokenStoreUserApprovalHandler
:一个简单的是/否决定通过
user_oauth_approval
等于“真”或“假”。

ApprovalStoreUserApprovalHandler
:具有
scope.*
等于所请求范围的“*”的一组参数键。该参数的值可以是“真”或“已批准”(如果用户批准了授权),则该用户被认为已经拒绝了该范围。如果批准了至少一个范围,则赠款将成功。

注意:不要忘记在您为用户呈现的表单中包含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")
)。

将用户角色映射到范围

限制标记的范围有时也不仅仅是分配给客户端的范围,还可以根据用户自己的权限。如果您在其中使用
DefaultOAuth2RequestFactory
,则
AuthorizationEndpoint
可以设置一个标志,
checkUserScopes=true
以将允许的范围限制为只匹配用户角色的范围。你也可以注入一个
OAuth2RequestFactory
TokenEndpoint
但只有工作(即密码授权),如果你也安装一个
TokenEndpointAuthenticationFilter
- 你只需要添加该过滤器之后的HTTP
BasicAuthenticationFilter
。当然,您还可以实现自己的规则,将作用域映射到角色并安装自己的版本
OAuth2RequestFactory
。将
AuthorizationServerEndpointsConfigurer
让你注入一个定制的
OAuth2RequestFactory
,所以你可以使用该功能来建立一个工厂,如果你使用
@EnableAuthorizationServer


资源服务器配置

资源服务器(可以与授权服务器或单独的应用程序相同)提供受OAuth2令牌保护的资源。Spring OAuth提供实现此保护的Spring Security认证过滤器。您可以
@EnableResourceServer
@Configuration
类上打开它,并使用a进行配置(如有必要)
ResourceServerConfigurer
。可以配置以下功能:

tokenServices
:定义令牌服务的bean(实例
ResourceServerTokenServices
)。

resourceId
:资源的ID(可选,但建议并由验证服务器验证,如果存在)。

其他解决方案服务器的扩展点(例如
tokenExtractor
从传入请求中提取令牌)

请求匹配的受保护资源(默认为全部)

受保护资源的访问规则(默认为“已验证”)

HttpSecurity
Spring 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实现,但如果您希望实现自己的服务来将持久性数据库中的访问令牌和关联的身份验证实例存储起来,那么您可以使用。如果要使用此功能,您需要提供特别配置
TokenProvider
OAuth2RestTemplate
例如

@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.INTERFACES)
public OAuth2RestOperations restTemplate() {
OAuth2RestTemplate template = new OAuth2RestTemplate(resource(), new DefaultOAuth2ClientContext(accessTokenRequest));
AccessTokenProviderChain provider = new AccessTokenProviderChain(Arrays.asList(new AuthorizationCodeAccessTokenProvider()));
provider.setClientTokenServices(clientTokenServices());
return template;
}


外部OAuth2提供商客户端的定制

一些外部OAuth2提供者(例如Facebook)并没有正确地实现规范,或者他们只是停留在旧版本的规范上,而不是Spring Security OAuth。要在客户端应用程序中使用这些提供程序,您可能需要调整客户端基础架构的各个部分。

要以Facebook为例,
tonr2
应用程序中有一个Facebook功能(您需要更改配置以添加您自己的,有效的客户端ID和密码 - 它们很容易在Facebook网站上生成)。

Facebook令牌响应还会在令牌的到期时间内包含一个不合规的JSON条目(它们使用
expires
而不是
expires_in
),因此如果要在应用程序中使用到期时间,则必须使用自定义手动解码
OAuth2SerializationService
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: