这是 OAuth 2.0 的用户指南。OAuth 1.0 与之大不相同,若有需求,请阅读 1.0 的用户指南 。
本用户指南分为两个部分,一部分针对的是 OAuth 2.0 的提供方[译者注:通常指服务提供方],另一部分则是针对 OAuth 2.0 客户端。对于提供方和客户端双方来说,最好的示例代码是 集成测试 和 示例应用 。
OAuth 2.0 提供方通过某种机制来提供受 OAuth 2.0 保护的资源。其配置涉到确立 OAuth 2.0 客户端能做什么,是能独立访问受保护的资源,还是保护用户的利益。提供方通过管理和验证 OAuth 2.0 令牌达到目的,令牌就是用来访问受保护资源的。在某些情况下,提供方还必须为用户提供一个接口用于确认授权客户端访问受保护的资源(比如,确认页面)。
OAuth 2.0 的提供方实际涵盖两个角色,即认证服务 (Authorization Service) 和资源服务 (Resource Service),有时候它们会在同一个应用程序中实现。使用 Spring Security OAuth 的时候你可以选择把把它们分别放在两个应用程序中,也可以选择建立使用同一个认证服务的多个资源服务。对令牌的请求由 Spring MVC 控制器终端进行处理,而标准的 Spring security 请求过滤器会处理对受保护资源的访问。Spring以 Security 过滤器链需要以下各端来实现 OAuth 2.0 认证服务:
AuthorizationEndpoint
服务于认证请求。默认 URL: /oauth/authorize
。
TokenEndpoint
服务于访问令牌的请求。默认 URL: /oauth/token
。
下面的过滤器用于实现 OAuth 2.0 资源服务:
OAuth2AuthenticationProcessingFilter 用来对请求给出的身份令牌加载认证。
在所有 OAuth 2.0 提供方特性中,使用 Spring OAuth @Configuraton 注解来进行配置是最简单的。OAuth 配置也有自己的 XML 命名空间,它的结构描述在 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
,其命名空间是 http://www.springframework.org/schema/security/oauth2
。
在配置授权服务器时,您必须考虑客户端用来从最终用户获取访问令牌的授权类型(例如,授权码,用户凭证,刷新令牌)。服务器的配置用于提供客户端详细信息服务和令牌服务的实现,并启用或禁用全局机制的某些方面。但是请注意,每个客户端都可以配置特定的权限,以便能够使用某些授权机制和访问权限。即仅仅因为您的提供程序配置为支持“客户端凭据”授予类型,并不意味着特定的客户端有权使用该授予类型。
@EnableAuthorizationServer
注解用于配置 OAuth 2.0 授权服务器机制,以及实现 AuthorizationServerConfigurer
的任何 @Beans
(有一个使用空方法的方便的适配器实现)。以下功能委托给由 Spring 创建并传递给 AuthorizationServerConfigurer
的独立配置器:
ClientDetailsServiceConfigurer
:定义客户端详细信息服务的配置器。客户详细信息可以初始化,或者可以引用现有的 store
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 服务的 schema 未与库打包(因为在实践中可能会有太多的变化),但是你可以从 test code in github 这个例子开始。
AuthorizationServerTokenServices
接口定义了管理 OAuth 2.0 token 的必要操作。请注意以下几点:
当创建一个可访问 Token 时, 身份认证必须存储起来,以便接受可访问 Token 的资源后面可作为引用。
可访问的 Token 用来加载授权创建的身份验证。
当你创建了 AuthorizationServerTokenServices
的实现后,你可能会考虑使用
DefaultTokenServices
,这个接口中有多种方法,可以用来改变访问 Token 的格式和存储。默认情况下使用随机值创建 token 并处理所有的内容,除了委托给 TokenStore 的 token 持久化操作。默认存储方式是 在内存中实现
,不过也支持另外的实现方式。下面为你介绍其他实现方式。
默认的 InMemoryTokenStore 在单个服务器上表现良好(少量传输且失败时不通过热插拔更换到备份服务器)。多数项目都可以从它开始,也可以在开发模式中使用,它可以直接启动,没有其它依赖。
JdbcTokenStore 是同一个东西,不过是 JDBC 版本 ,它把数据保存在关系型数据库中。使用 JDBC 版本可以实现在多个服务器上共享数据库,如果只有一台服务器也可以直接在上面部署服务,或者在有多个组件的情况下使用认证和资源服务器。要使用 JdbcTokenStore,需要在 classpath 中配置 "spring-jdbc"。
JSON Web Token (JWT) 版本 将所有授权相关的数据通过编码后存储起来(没使用后端存储是其显著优势)。它的缺点是不能轻易地撤消访问令牌,因此它们的有效时间通常都很短,在更新令牌的时候处理撤消。还有一个缺点是,如果令牌存储了大量的用户凭据信息,它就可能变得相当大。不过在 DefaultTokenServices 中,它起着翻译令牌值和认证信息的作用。
注意:针对 JDBC 服务的架构所需要的库并未打包在其中(因为在实际使用中有太多不确定因素),不过你可以把 Github 上的测试代码 作为示例,从这里开始。一定要使用 @EnableTransactionManagement 来防止在多个客户端创建令牌时产生行数据冲突。还要注意示例架构有明确的主键(PRIMARY KEY)声明——这些在开发环境中也是必需的。
需要在认证服务器中加入 JwtTokenStore 来支持 JWT 令牌。资源服务器要能对令牌进行解码,所以 JwtTokenStore 会依赖 JwtAccessTokenConverter,而且认证服务器和资源服务器要有相同的实现。默认情况下令牌会有签名,而资源服务器也要能验证印鉴,所以它需要与授权服务器相同的对称(签名)密钥(共享密钥或对称密钥),或者,它需要一个与认证服务器所使用的私钥配对的公钥(验证密钥)(公私密钥或非对称密钥)。公钥(如果有的话)会由认证服务器通过 /oauth/token_key 提供,这个地址默认情况下是通过 “deenyAll()” 来保护的。你可以向 AuthorizationServerSecurityConfigurer 注入一个标准的 SpEL 表达式(比如 “permitAll()” 就可以,因为那是公钥)来放开保护限制。
使用 JwtTokenStore 的时候你需要在 classpath 中有 "spring-security-jwt"(你可以在 Spring OAuth 所在的 github 库的另一个发布周期中找到)。
AuthorizationEndpoint 支持的授权类型可以通过 AuthorizationServerEndpointsConfigurer 进行配置。 默认情况下,除了密码之外,所有的授权类型都是受支持的(请参阅下面的关于如何打开的细节)。 以下属性影响授权类型:
authenticationManager:通过注入 AuthenticationManager 来开启密码授权。
userDetailsService:如果你注入一个 UserDetailsService,或者全局地配置了一个UserDetailsService(例如在 GlobalAuthenticationManagerConfigurer中),那么刷新令牌授权将包含对用户详细信息的检查,以确保该帐户仍然是活动的
authorizationCodeServices:为授权代码授权定义授权代码服务(AuthorizationCodeServices 的实例)。
implicitGrantService:在 imlpicit 授权期间管理状态。
tokenGranter:TokenGranter(完全控制授予和忽略上面的其他属性)
在 XML 中,授权类型作为授权服务器的子元素被包含在内。
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 }