Spring Security OAuth 2开发者指南
GuoMengYue 发表于2周前
Spring Security OAuth 2开发者指南
  • 发表于 2周前
  • 阅读 997
  • 收藏 73
  • 点赞 2
  • 评论 3

330元/年抢阿里云香港云服务器,节省80%出海成本>>>   

介绍

这个用户指南支持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过滤器链中需要以下端点:

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

对于所有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对于单个服务器,默认值是完全正确的(即,在出现故障的情况下,流量不足,备份服务器无热插拔)。大多数项目可以从这里开始,也可以在开发模式下运行,以便轻松启动没有依赖关系的服务器。

  • JdbcTokenStoreJDBC版本的同样的事情,这在关系数据库中存储令牌数据。如果您可以在服务器之间共享数据库,则可以使用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取决于您是否ApprovalStoreAuthorizationServerEndpointsConfigurer(在这种情况下是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以将允许的范围限制为只匹配用户角色的范围。你也可以注入一个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为例,tonr2应用程序中有一个Facebook功能(您需要更改配置以添加您自己的,有效的客户端ID和密码 - 它们很容易在Facebook网站上生成)。

Facebook令牌响应还会在令牌的到期时间内包含一个不合规的JSON条目(它们使用expires而不是expires_in),因此如果要在应用程序中使用到期时间,则必须使用自定义手动解码OAuth2SerializationService

共有 人打赏支持
GuoMengYue
粉丝 16
博文 12
码字总数 120515
作品 1
评论 (3)
就一身傲骨
飞翔1000VPN 高速翻墙,Youtube、Facebook、Twitter、Tumbl、google搜索等等,限时免费领取试用帐号,官网:http://t.cn/RKiZmbK
哎码
看不懂....
大-王
这只是其中一种模式吧, 我现在用的是password模式
×
GuoMengYue
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: