超越
VMware 提供培训和认证,为您的进步加速。
了解更多Spring Boot 1.3 中有一些与 OAuth2 客户端、服务器以及 Spring Security OAuth2 相关的新特性。其中一些特性从 Spring Cloud Security 移植而来,因此它们曾在 Spring Cloud 的 Angel 发布系列中,但不在 Brixton 发布系列中。本文将帮助您了解这些变化并更新现有应用以使用新特性。
如果您没有使用 Spring Cloud,您应该只需要更改 Spring Boot 依赖项的版本号即可。由于一些 OAuth2 特性在 1.3 版本中从 Spring Cloud Security 迁移到了 Spring Boot,情况可能会稍微复杂一些。另一篇文章专门讨论了如何将 Spring Cloud 应用从 Spring Boot 1.2 升级到 1.3。如果您正在使用 Spring Cloud Angel 发布系列,您应该查阅那篇文章以获取有关如何管理依赖项的详细信息(独立于任何特定功能)。
OAuth2 授权服务器的首要职责是颁发访问令牌。为此,它必须能够对客户端应用和(可选地)用户进行身份验证。
Spring Boot 1.3 中,可以通过约定和一些配置属性实现一个非常简单的、只包含一个客户端的 OAuth2 授权服务器。因此,像 spring.io 上 Angular JS Spring Security 教程 中的基础授权服务器示例就可以大大简化。在 Spring Boot 1.2 中,我们需要:
@SpringBootApplication
@RestController
@EnableResourceServer
public class AuthserverApplication {
@Configuration
@EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Excep
endpoints.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("acme")
.secret("acmesecret")
.authorizedGrantTypes("authorization_code", "refresh_token",
"password")
.scopes("openid").autoApprove(true);
}
}
...
}
在 Spring Boot 1.3 中,我们只需要:
@SpringBootApplication
@RestController
@EnableResourceServer
@EnableAuthorizationServer
public class AuthserverApplication {
...
}
并在 application.properties
中进行如下配置:
security.oauth2.client.clientId: acme
security.oauth2.client.clientSecret: acmesecret
security.oauth2.client.authorized-grant-types: authorization_code,refresh_token,password
security.oauth2.client.scope: openid
这是一个通用授权服务器,非常适合演示,但在实践中不太现实,因为它只有一个客户端 ("acme")。尽管如此,作为快速入门 OAuth2 的方法,用如此少的代码就能实现这么多功能是很不错的。
要扩展基本示例并控制授权服务器特性,您只需要回到旧的 Spring Boot 1.2 版本(任何带有自己的 AuthorizationServerConfigurer
的应用都会关闭自动配置的特性)。
资源服务器通过要求提供有效的访问令牌(由授权服务器创建)来保护其端点。
与授权服务器类似,资源服务器也可以通过约定和一些配置属性在 Spring Boot 1.3 中实现,或者通过 Spring Boot 1.2 结合 Spring Cloud Security 来实现。例如,考虑 spring.io 上 Angular JS Spring Security 教程 中的基础资源服务器。
在 Spring Boot 1.2 中,我们必须使用 Spring Cloud Security 来获取 @EnableOAuth2Resource
注解
@SpringBootApplication
@RestController
@EnableOAuth2Resource
class ResourceApplication {
...
}
并在 application.properties
中进行一些配置以帮助解码访问令牌
spring.oauth2.resource.userInfoUri: http://localhost:9999/uaa/user
在 Spring Boot 1.3 中,可以移除 Spring Cloud 依赖项,并将注解替换为 Spring Security OAuth2 中的基础 @EnableResourceServer
注解
@SpringBootApplication
@RestController
@EnableResourceServer
class ResourceApplication {
...
}
为了完成应用,配置略有不同(注意 key 前缀从 spring.oauth2
变更为 security.oauth2
)
security.oauth2.resource.userInfoUri: http://localhost:9999/uaa/user
在 OAuth2 中,客户端是一个代理(通常是应用程序),它获取令牌,通常是代表用户。可以通过拥有一个单独的授权服务器和作为 OAuth2 客户端的依赖认证应用来实现单点登录(Single Sign On)。
在 Spring Boot 1.3 的客户端,您可以通过注解和一些配置属性来实现单点登录模式。如果您同时使用 Spring Cloud Security,在 Spring Boot 1.2 中也可以实现相同的功能。
一个使用 Spring Boot 1.2 和 Spring Cloud Angel 的通用示例会使用一个简单的 @EnableOAuth2Sso
注解
@SpringBootApplication
@EnableOAuth2Sso
public class SsoApplication {
...
}
并在 application.yml
(或等效的 application.properties
)中对客户端进行一些配置。这是一个使用 Facebook 进行身份验证的示例,适用于运行在 localhost:8080 上的应用
spring:
oauth2:
client:
clientId: 233668646673605
clientSecret: 33b17e044ee6a4fa383f46ec6e28ea1d
accessTokenUri: https://graph.facebook.com/oauth/access_token
userAuthorizationUri: https://#/dialog/oauth
tokenName: oauth_token
authenticationScheme: query
clientAuthenticationScheme: form
resource:
userInfoUri: https://graph.facebook.com/me
同一个应用在 Spring Boot 1.3 中看起来几乎相同,但不再需要 Spring Cloud Security。此外,注解移动到了不同的包,并且配置前缀也发生了变化。因此,迁移此应用所需的全部操作是移除 Cloud 依赖项,更改注解的导入,并将 application.yml
中的前缀从 spring
切换到 security
。
在 Spring Cloud Security 1.0 (Angel 发布系列) 中,用户可以使用特殊的 callback OAuth2ClientConfigurer
和 spring.oauth2.sso.*
中的一些配置属性来组合自定义请求匹配和访问规则。例如,spring.io 上 Angular JS Spring Security 教程 中的基础客户端应用在 Spring Boot 1.2 中具有以下通用实现模式:
@SpringBootApplication
@EnableOAuth2Sso
public class UiApplication {
@Configuration
protected static class SecurityConfiguration extends OAuth2SsoConfigurerAdapter {
@Override
public void match(RequestMatchers matchers) {
matchers.anyRequest();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/index.html", "/home.html", "/").permitAll()
.anyRequest().authenticated()
.and().csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
}
...
}
以及一个类似于基础示例的 application.yml
spring:
oauth2:
sso:
home:
secure: false
path: /,/**/*.html
client:
accessTokenUri: http://localhost:9999/uaa/oauth/token
userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize
resource:
userInfoUri: http://localhost:9999/uaa/user
在 Spring Boot 1.3 中,不再需要 Spring Cloud Security,并且自定义也不需要废弃的 OAuth2SsoConfigurerAdapter
。相反,它们只需要将所有相同的代码以及一个请求匹配器放在一个带有 @EnableOAuth2Sso
注解的普通 WebSecurityConfigurerAdapter
中即可。
@SpringBootApplication
@EnableZuulProxy
@EnableOAuth2Sso
public class UiApplication extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/index.html", "/home.html", "/").permitAll()
.anyRequest().authenticated()
.and().csrf()
.csrfTokenRepository(csrfTokenRepository())
.and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
}
...
}
更新版本中的配置属性大部分相同:前缀从 spring.oauth2
更改为 security.oauth2
,并且不再需要 *.oauth2.sso.*
属性,因为它们由用户在 WebSecurityConfigurerAdapter
中显式配置。
spring.io 上 Angular JS Spring Security 教程 中的实际客户端应用类似于上面的自定义示例,但它也是一个 Zuul 代理,负责将来自浏览器客户端的请求转发到后端服务。在 Spring Boot 1.3 中,此应用仍然需要 Spring Cloud Security 来进行令牌转发(它希望将用于身份验证的访问令牌发送到后端资源),但对于基本的 SSO 特性不再需要它,因此其实现与前一个示例相同,只是额外添加了 @EnableZuulProxy
注解。
注意:Spring Boot 1.3.0 中的一个 bug 导致在当前实现(撰写本文时)中,Angular JS Spring Security 教程 的客户端应用需要一个 workaround。这个 workaround 只是因为使用了 Spring Cloud Security 才需要,在 Spring Boot 1.3.1 中也将不再需要。
@Component @Order(Ordered.HIGHEST_PRECEDENCE) class WorkaroundRestTemplateCustomizer implements UserInfoRestTemplateCustomizer { public void customize(OAuth2RestTemplate template) { template.setInterceptors(new ArrayList<>(template.getInterceptors())); } }
在 Spring Boot 1.2 和 Spring Cloud Angel 发布系列中,如果您的应用绑定到具有正确凭据的服务,它就能自动配置 OAuth2 SSO。例如,您可以创建一个用户提供的服务 (User Provided Service),如下所示:
cf create-user-provided-service sso -p '{"userInfoUri":"https://uaa.run.pivotal.io/userinfo", "tokenUri":"login.run.pivotal.io/oauth/token", "authorizationUri":"login.run.pivotal.io/oauth/authorize", "clientId":"[client]", "clientSecret":"[secret]"}'
然后,绑定到该服务的带有 @EnableOAuth2Sso
注解的应用将绑定 SSO 所需的配置,而用户无需更改任何配置。
Spring Boot 1.3 和 Spring Cloud Brixton 中也提供了相同的功能,但您需要使用新的 spring-cloud-cloudfoundry-web
库来获得 SSO 配置绑定行为,而不是使用 Spring Cloud Security。您还可以使用 Cloud Foundry 内置的 SSO 服务,而不是用户提供的服务(在 Pivotal Web Services 中适用于特定账户,或在 Pivotal Cloud Foundry 中可用)。
如果您正在使用 Spring Boot,或者可能同时使用 Spring Cloud 和 OAuth2,希望您现在能够顺利地从 Spring Boot 1.2 升级到 1.3,或者至少在遇到问题时有一些工具帮助您思考。Spring Boot 1.3 几乎包含了 Spring Cloud Security 1.0 的所有功能,所以您主要需要考虑的是依赖项。此外,Spring Boot 中还有一些新特性,例如授权服务器的自动配置。像使用 Spring Boot 的常态一样,您可以(并且应该)在需要更改之前一直使用默认行为,一旦需要更改,应该没有任何障碍。
Spring 指南中的示例应用现在都已更新到 Spring Boot 1.3,即使这意味着它们依赖于 Spring Cloud 的里程碑版本(这仅适用于 Zuul 代理示例)。许多应用不再需要 Spring Cloud。如果您需要 Spring Cloud 的 GA 版本,您现在需要停留在 Spring Boot 1.2。该组合的示例可以从 git 历史记录中获取。