82. More Detail

82.1 单点登录

Note

所有 OAuth2 SSO 和资源服务器功能已在 1.3 版中移至 Spring Boot。您可以在Spring Boot 用户指南中找到文档。

82.2 令牌中继

令牌中继是 OAuth2 使用者充当 Client 端并将传入令牌转发到传出资源请求的地方。使用者可以是纯 Client 端(如 SSO 应用程序)或资源服务器。

Spring Cloud Gateway 中的 Client 端令牌中继

如果您的应用程序还具有Spring Cloud Gateway嵌入式反向代理,则可以要求它向下游转发 OAuth2 访问令牌到它正在代理的服务。因此,可以像下面这样简单地增强上面的 SSO 应用程序:

App.java.

@Autowired
private TokenRelayGatewayFilterFactory filterFactory;

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
            .route("resource", r -> r.path("/resource")
                    .filters(f -> f.filter(filterFactory.apply()))
                    .uri("http://localhost:9000"))
            .build();
}

or this

application.yaml.

spring:
  cloud:
    gateway:
      routes:
      - id: resource
        uri: http://localhost:9000
        predicates:
        - Path=/resource
        filters:
        - TokenRelay=

它将(除了登录用户并获取令牌之外)还将身份验证令牌传递给服务(在本例中为/resource)。

要为 Spring Cloud Gateway 启用此功能,请添加以下依赖项

  • org.springframework.boot:spring-boot-starter-oauth2-client

  • org.springframework.cloud:spring-cloud-starter-security

它是如何工作的? filter从当前经过身份验证的用户中提取访问令牌,并将其放入下游请求的请求 Headers 中。

有关完整的工作示例,请参见this project

82.2.2Client 端令牌中继

如果您的应用是面向 OAuth2Client 端的用户(即已声明@EnableOAuth2Sso@EnableOAuth2Client),则它在 Spring Boot 的请求范围内为OAuth2ClientContext。您可以从此上下文中创建自己的OAuth2RestTemplate并自动连接OAuth2ProtectedResourceDetails,然后上下文将始终将访问令牌转发到下游,如果过期,访问令牌也会自动刷新。 (这些是 Spring Security 和 Spring Boot 的功能.)

Note

如果您使用的是client_credentials令牌,Spring Boot(1.4.1)不会自动创建OAuth2ProtectedResourceDetails。在这种情况下,您需要创建自己的ClientCredentialsResourceDetails并将其配置为@ConfigurationProperties("security.oauth2.client")

Zuul 代理中的 Client 端令牌中继 82.2.3

如果您的应用程序还具有Spring Cloud 祖尔嵌入式反向代理(使用@EnableZuulProxy),则可以要求它向下游转发 OAuth2 访问令牌到它正在代理的服务。因此,可以像下面这样简单地增强上面的 SSO 应用程序:

app.groovy.

@Controller
@EnableOAuth2Sso
@EnableZuulProxy
class Application {

}

它将(除了登录用户并获取令牌之外)还将身份验证令牌向下传递到/proxy/*服务。如果这些服务是通过@EnableResourceServer实现的,则它们将在正确的 Headers 中获得有效的令牌。

它是如何工作的? @EnableOAuth2Sso注解引入spring-cloud-starter-security(您可以在传统应用程序中手动完成),进而触发ZuulFilter的一些自动配置,该ZuulFilter本身被激活,因为 Zuul 在 Classpath 上(通过@EnableZuulProxy)。 filter只是从当前经过身份验证的用户中提取访问令牌,并将其放入下游请求的请求 Headers 中。

82.2.4 资源服务器令牌中继

如果您的应用具有@EnableResourceServer,则您可能希望将传入令牌下游中继到其他服务。如果您使用RestTemplate与下游服务联系,那么这只是如何在正确的上下文中创建模板的问题。

如果您的服务使用UserInfoTokenServices对传入令牌进行身份验证(即使用security.oauth2.user-info-uri配置),则只需使用自动连接的OAuth2ClientContext创建一个OAuth2RestTemplate(它将在身份验证过程中填充到后端代码之前填充)。同样(在 Spring Boot 1.4 中),您可以在配置中注入UserInfoRestTemplateFactory并获取其OAuth2RestTemplate。例如:

MyConfiguration.java.

@Bean
public OAuth2RestTemplate restTemplate(UserInfoRestTemplateFactory factory) {
    return factory.getUserInfoRestTemplate();
}

然后,该其余模板将具有与身份验证filter使用的相同的OAuth2ClientContext(请求范围),因此您可以使用它来发送具有相同访问令牌的请求。

如果您的应用未使用UserInfoTokenServices但仍是 Client 端(即它声明了@EnableOAuth2Client@EnableOAuth2Sso),则使用 Spring Security Cloud 用户从@Autowired @OAuth2Context创建的任何OAuth2RestOperations也会转发令牌。默认情况下,此功能作为 MVC 处理程序拦截器实现,因此仅在 Spring MVC 中有效。如果不使用 MVC,则可以使用包装AccessTokenContextRelay的自定义filter或 AOP 拦截器来提供相同的功能。

这是一个基本示例,展示了如何使用在其他位置创建的自动连接的 Rest Template(“ foo.com”是接受与周围应用程序相同的令牌的资源服务器):

MyController.java.

@Autowired
private OAuth2RestOperations restTemplate;

@RequestMapping("/relay")
public String relay() {
    ResponseEntity<String> response =
      restTemplate.getForEntity("https://foo.com/bar", String.class);
    return "Success! (" + response.getBody() + ")";
}

如果您不希望转发令牌(这是一个有效的选择,因为您可能想扮演自己的角色,而不是向您发送令牌的 Client 端),那么您只需要创建自己的OAuth2Context而不是自动装配默认一个。

Feign的 Client 还将选择使用OAuth2ClientContext的拦截器(如果可用),因此他们也应在RestTemplate会出现的任何地方进行令牌中继。