使用 Spring boot、Eureka、Zuul、Spring Oauth 创建 OAuth 安全微服务的问题

Posted

技术标签:

【中文标题】使用 Spring boot、Eureka、Zuul、Spring Oauth 创建 OAuth 安全微服务的问题【英文标题】:Issues creating OAuth secured Microservices using Spring boot, Eureka, Zuul, Spring Oauth 【发布时间】:2016-11-13 16:06:05 【问题描述】:

我正在尝试使用 Spring Boot、Eureka、Zuul 和 Spring OAuth 设置 Zuul 反向代理。具体来说,我正在尝试从 Zuul 后面的 OAuth 服务器获取 OAuth 不记名令牌。为此,我需要向重定向到我们的 OAuth 服务器的代理端点发出 POST 请求。此请求使用 client_credentials 授权类型,因此使用 BasicAuth 来获取不记名令牌。我已经验证可以绕过Zuul获取token。

我在获得预期结果时遇到了麻烦,它是一个支持 OAuth 的反向代理,但本身没有必需的安全性。我尝试了几种不同的配置变体,但找不到金票。

这是我的 Maven:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.mycompany.cloud</groupId>
    <artifactId>mycompany-cloud</artifactId>
    <version>0.0.2-SNAPSHOT</version>
  </parent>
  <artifactId>mycompany-cloud-zuul-proxy</artifactId>

  <dependencies>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zuul</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.security.oauth</groupId>
      <artifactId>spring-security-oauth2</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>Brixton.SR2</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>1.3.5.RELEASE</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>repackage</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

我最初创建的配置只是

@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
@EnableOAuth2Sso
public class ZuulProxyApplication 
  public static void main(final String[] args) 
    SpringApplication.run(ZuulProxyApplication.class, args);
  

但这默认启用基本身份验证安全性。我知道这一点是因为我会在发出任何 POST 请求时得到 CSRF 错误。设置security.enable-csrf=false 并没有禁用它(我发现这很奇怪)。设置security.basic.enabled=false 也没有禁用任何安全性也很奇怪。我终于注意到@EnableOAuth2Sso 上的JavaDoc 说如果没有提供WebSecurityConfigurerAdapter,那么它将使用默认值。我尝试将@EnableWebSecurity 添加到我应该添加WebSecurityConfigurerAdapter 的配置中,但我的POST 请求仍然出现CSRF 错误。也许默认它使用不知道SecurityProperties。所以我最终得到了这个配置:

@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ZuulProxyApplication 

  public static void main(final String[] args) 
    SpringApplication.run(ZuulProxyApplication.class, args);
  

  @Configuration
  @EnableOAuth2Sso
  @EnableWebSecurity
  @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
  protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter 

    @Autowired
    public void globalUserDetails(final AuthenticationManagerBuilder auth) throws Exception 
      // add no users
      auth.inMemoryAuthentication();
    

    @Override
    protected void configure(final HttpSecurity http) throws Exception 
      http.csrf().disable();
    

  

以及以下属性:

spring:
  application:
    name: mycompany-cloud-zuul-proxy
    index: 0
security:
  oauth2:
    client:
      access-token-uri: http://mycompany-cloud-authorization-server/oauth/token
      user-authorization-uri: http://mycompany-cloud-authorization-server/oauth/authorize
  basic:
    enabled: false
  enable-csrf: false
  sessions: stateless
server:
  port: 9200
eureka:
  client:
    service-url:
      defaultZone: http://localhost:9100/eureka/

这很成功,它禁用了 CSRF 配置,我能够在没有收到 CSRF 错误的情况下向我的服务发出 POST 请求。但是,现在我的 OAuth 服务器拒绝请求,因为 BasicAuth 标头不再出现在请求中。 Zuul 似乎正在剥离标题。我是否误解了添加 @EnableOAuth2Sso 注释会使应用程序知道 OAuth 并且它将允许访问已配置的 OAuth 服务器的方法,或者它是否仅适用于 Bearer 令牌?将您的 OAuth 服务器放在代理后面是否正常,或者这不是预期的事情?我猜我遗漏了一些我尚未从文档中理解的重要知识和/或配置。

如有任何帮助,我们将不胜感激。

【问题讨论】:

【参考方案1】:

但是,现在我的 OAuth 服务器拒绝请求,因为 BasicAuth 标头不再在请求中

默认情况下,Spring cloud Zuul 实现会出于安全目的剥离一些标头(请参阅Cookies and sensitive headers documentation)

因此,由于 Spring cloud netflix 1.1 以下标头 Cookie, Set-Cookie, Authorization 被认为是合理的标头

将您的 OAuth 服务器放置在代理后面是否正常,或者这不是预期的事情?

Spring cloud 基本上没有默认设计为在代理 (Zuul) 后面有授权服务器(或 OAuth 服务器)。在大多数示例和文档中,授权服务器位于代理之外。

我亲自创建了一个 POC,用于Proxy 背后的授权 https://github.com/kakawait/uaa-behind-zuul-sample,它可能(或不会)帮助您。

【讨论】:

这一切似乎都是针对基于用户的 oauth 量身定制的。我们主要还需要支持授权类型 client_credentials 并最终支持所有其他授权类型。我已经根据您提供的一些代码,将接收到的不记名令牌传递给它调用的其他服务的服务工作,但现在我正试图让 zuul 代理做同样的事情。我开始觉得为 @EnableOAuthSso 构建的所有内容都是针对涉及实际用户的 OAuth 方案(例如,不是 client_credentials)量身定制的。是这样吗? 根据我对@EnableOauthSso 的理解,您不能使用client_credentials,因为SSO 是为人和浏览器设计的。如果某些路由需要与 client_credentials 一起使用,只需删除此路由上的 SSO。但是,如果您的路线应该同时支持我认为目前不可能,您可以打开问题或直接与​​ Spring 家伙在 gitter 上询问 好的。很好地验证了我的假设。我找不到任何地方说它仅适用于基于用户的 oauth。我认为 SSO 也应该能够用于基于机器的身份验证以及基于用户的身份验证。我期望它工作的方式是盲目地将不记名令牌(或预先验证它们)传递给被调用的后端服务,并将用户路由到登录/授权页面的路由基于 oauth 服务器正在使用的授权类型。没想到还不止这些。 我确实最终让授权服务器(大部分)在 Zuul 后面工作。然而,由于出现了一些问题,我最终从 Zuul 后面移除。一个问题是,授权服务器将重定向发送回登录页面以进行基于用户的身份验证。此重定向在构建重定向 URL 时考虑了正常的 X-Forwarded-* 标头,但是它没有考虑 Zuul 添加的 X-Forwarded-Path 标头,因为大多数端点都代理在特定路径后面(zuul/uaa/v1* -> auth*) 和 Zuul 不是开箱即用的 ReverseProxy 您在身份验证服务器上使用了ForwardedHeaderFilter 吗?我个人对这种架构的路径和转发头没有问题。

以上是关于使用 Spring boot、Eureka、Zuul、Spring Oauth 创建 OAuth 安全微服务的问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 Eureka 服务集成测试 Spring Boot 服务

Zuu网关无法路由

Spring Boot集成Eureka

使用 Spring boot、Eureka、Zuul、Spring Oauth 创建 OAuth 安全微服务的问题

没有 Spring-boot 的 Eureka 服务发现

使用 Eureka 和 Docker Swarm 的 Spring Boot Admin