【问题标题】:Configuring embedded Jetty 9 for X-FORWARDED-PROTO with Spring Boot使用 Spring Boot 为 X-FORWARDED-PROTO 配置嵌入式 Jetty 9
【发布时间】:2014-12-07 15:43:42
【问题描述】:

我正在 AWS 中运行 Spring Boot 应用程序。该应用程序在弹性负载均衡器 (ELB) 后面运行。 ELB 配置为使用https(端口443)到外部世界,但通过http(端口8080)到应用程序。 ELB 配置为通过x-forwarded-proto 标头。我正在使用 Jetty 9.0.0.M0,使用 Spring Boot 1.1.5 RELEASE

我似乎收到了通过 ELB 从应用程序返回的错误重定向,其中重定向响应返回为 http,而不是 https。现在,我读到 here 应该将“转发”标题设置为 true 使用:

<Set name="forwarded">true</Set>

我看不到如何在 Spring Boot 中使用嵌入式版本的 Jetty 执行此操作,因为我的源代码中没有 XML 配置文件。

我查看了EmbeddedServletContainerCustomizer 基础架构,但我仍然无法获得正确的咒语来使此设置正常工作。

该应用程序是在 AWS https 环境之外构建和测试的,因此该应用程序还需要透明地使用 http。无需通过 ELB 即可直接访问应用程序端点。只是 ELB 到应用程序的路由不起作用。

有什么想法吗?

【问题讨论】:

  • Jetty 9.0.0.M0 不是 Jetty 9 的稳定版本。(实际上,它是一个预发布/里程碑 0)。升级
  • 如何使用 Spring Boot 自定义 ServerConnector 及其关联的 HttpConfigurations? (显示代码)

标签: spring amazon-web-services https jetty


【解决方案1】:

我一直无法为这个问题找到一个简单的 Jetty 9 解决方案。除了建议我升级到更高版本的 Jetty(这是个好建议)我没有收到其他建议(此时,如您所见)

为了方便起见,我的解决方案是放弃 Jetty,转而使用嵌入式 tomcat,此功能只需在 application.properties 文件中进行配置即可。只需将以下行添加到application.properties

server.tomcat.remote_ip_header=x-forwarded-for

这似乎使用作为 Spring Boot 一部分的默认嵌入式 tomcat 来解决问题。

【讨论】:

    【解决方案2】:

    我自己也有类似的问题,在研究时偶然发现了你的问题。我发现这很容易以编程方式进行,但在 Jetty 文档中并没有真正解释。

    Jetty xml 配置文件的结构与 java API 的结构相匹配,因此您可以在代码中复制它。

    所以遵循 Jetty 指南,了解如何使用 XML 配置文件 here 进行配置

    我能够像这样以编程方式配置嵌入式服务器:

        Server server = new Server( port );
    
        // Create HTTP Config
        HttpConfiguration httpConfig = new HttpConfiguration();
    
        // Add support for X-Forwarded headers
        httpConfig.addCustomizer( new org.eclipse.jetty.server.ForwardedRequestCustomizer() );
    
        // Create the http connector
        HttpConnectionFactory connectionFactory = new HttpConnectionFactory( httpConfig );
        ServerConnector connector = new ServerConnector(server, connectionFactory);
    
        // Make sure you set the port on the connector, the port in the Server constructor is overridden by the new connector
        connector.setPort( port );
    
        // Add the connector to the server
        server.setConnectors( new ServerConnector[] { connector } );
    

    【讨论】:

    【解决方案3】:

    这就是我们刚刚使用 jetty-runner-9.3.6.jar 后面的 Spring 应用程序所做的工作。在我们的例子中,我们的 jetty.xml 还没有任何 addConnector,尝试仅添加 addConnector 会出错。

    在这里找到它 - https://github.com/george-hawkins/authsite/blob/2c5d61b984a328ef878216a3acfd0ad2593f81b1/src/main/config/etc/jetty.xml

      <New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
        <Call name="addCustomizer">
          <Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
        </Call>
      </New>
    
      <Call name="addConnector">
        <Arg>
          <New class="org.eclipse.jetty.server.ServerConnector">
            <Arg name="server"><Ref refid="Server" /></Arg>
            <Arg name="factories">
              <Array type="org.eclipse.jetty.server.ConnectionFactory">
                <Item>
                  <New class="org.eclipse.jetty.server.HttpConnectionFactory">
                    <Arg name="config"><Ref refid="httpConfig" /></Arg>
                  </New>
                </Item>
              </Array>
            </Arg>
            <Set name="port"><SystemProperty name="jetty.port" default="8080"/></Set>
          </New>
        </Arg>
      </Call>
    

    这样做是为了修改通过的 Request 对象,使其看起来像是不是通过代理来的(用任何可用和支持的 X-Forwarded 标头替换详细信息)。

    http://archive.eclipse.org/jetty/9.0.0.M4/apidocs/index.html?org/eclipse/jetty/server/ForwardedRequestCustomizer.html

    此定制程序查看 HTTP 请求以获取表明它已被一个或多个代理转发的标头。具体处理有:

    • X 转发主机
    • X 转发服务器
    • X-Forwarded-For
    • X-Forwarded-Proto

    如果存在这些标头,则更新请求对象,以便代理不会被视为请求所经过的连接的另一个端点

    【讨论】:

      【解决方案4】:

      我发现默认 Spring Boot Jetty 配置存在一些问题,其中最重要的是 SSLLabs Check 不喜欢启用的 SSL 算法。

      无论如何:我找到的解决方法是这样的:

         @Bean
         public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() 
         {
            // Deploy the nuclear option, kill the default Spring Boot factory
            // and replace with mine that disables extra crud.
            JettyEmbeddedServletContainerFactory fac = new JettyEmbeddedServletContainerFactory();
            // This allows ELB to work.
            fac.setUseForwardHeaders( true );
            return fac;
         }
      

      如果您想要 SSL 端到端,还需要设置许多其他 ELB 选项。我不得不使用命令行客户端进行一些调整,并将运行状况检查更改为 TCP:8443 b/c,因为 EC2 实例证书对负载均衡器来说无效。

      【讨论】:

        【解决方案5】:

        尝试在您的 Spring Boot 应用程序中设置以下属性:

        server.use-forward-headers=true
        

        这将确保从标头中读取正确的协议。请参阅此处的文档:

        https://docs.spring.io/spring-boot/docs/1.5.9.RELEASE/reference/html/howto-embedded-servlet-containers.html

        【讨论】:

          猜你喜欢
          • 2016-12-21
          • 2015-04-09
          • 1970-01-01
          • 2014-06-14
          • 1970-01-01
          • 2019-07-19
          相关资源
          最近更新 更多