首页 文章

在Apache代理后面嵌入Tomcat的Spring-boot

提问于
浏览
23

我们在Apache SSL代理后面的专用appserver上有一个带有嵌入式Tomcat的spring-boot / spring-mvc应用程序 .

代理服务器上的SSL端口为4433,转发到应用服务器上的端口8080 .

所以代理服务器的URL转发如下:

https://proxyserver:4433/appname   >>forward>>   http://appserver:8080/

运行WITHOUT代理时,首先发生的是
spring-security重定向请求,如:

http://appserver:8080/   >>redirect>>   http://appserver:8080/login

通过扩展 WebSecurityConfigurerAdapter 显示登录表单

...
  httpSecurity.formLogin().loginPage("/login") ...
  ...

它在没有代理的情况下工作正常,但是WITH代理需要更改重定向,因此Spring应该重定向到相应的代理URL,如:

http://appserver:8080/   >>redirect>>   https://proxyserver:4433/appname/login

但还没有成功 .

我正在尝试应用此解决方案:

http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#howto-use-tomcat-behind-a-proxy-server(59.8在前端代理服务器后面使用Tomcat)

我们在Apache中配置了mod_proxy,并验证它是否发送了预期的头文件:

X-Forwarded-For: xxx.xxx.xxx.xxx
X-Forwarded-Host: proxyserver
X-Forwarded-Port: 4433
X-Forwarded-Proto: https

应用程序以参数启动:

export ARG1='-Dserver.tomcat.protocol-header=x-forwarded-proto' 
export ARG2='-Dserver.tomcat.remote-ip-header=x-forwarded-for'
java $ARG1 $ARG2 -jar webapp.jar

仍然重定向不起作用 .

它将在本地重定向到 http://appserver:8080/login ,这是客户无法使用的 .

我们需要做些什么来使这个场景有效吗?

EDIT :另外,我担心代理网址中的"/appname"部分 . 在appserver上,应用程序的根目录是"/" . 如何指示在通过代理时,应该将"/appname"包含在发送回客户端的所有URL中?

6 回答

  • 4

    前几天我遇到了同样的问题 . 经过Spring Boot 1.3的一些调试后,我找到了以下解决方案 .

    1. 您必须在Apache代理上设置标头:

    <VirtualHost *:443>
        ServerName www.myapp.org
        ProxyPass / http://127.0.0.1:8080/
        RequestHeader set X-Forwarded-Proto https
        RequestHeader set X-Forwarded-Port 443
        ProxyPreserveHost On
        ... (SSL directives omitted for readability)
    </VirtualHost>
    

    2. 您必须告诉Spring Boot应用程序使用这些标头 . 所以将以下行放在application.properties(或Spring Boots了解属性的任何其他地方)中:

    server.use-forward-headers=true
    

    如果你正确地做了这两件事,你的应用程序发送的每个重定向都会 not 转到http://127.0.0.1:8080/[path]但会自动转到https://www.myapp.com/[path]

    更新1.有关此主题的文档是here . 您应该至少阅读它以了解属性 server.tomcat.internal-proxies ,该属性定义了可信任的代理服务器的IP地址范围 .

  • 0

    您的代理看起来很好,后端应用程序也是如此,但是它似乎没有看到 RemoteIpValve 已修改的请求 . RemoteIpValve 的默认行为包括代理IP地址的模式匹配(作为安全检查),它仅修改它认为来自有效代理的请求 . Spring Boot中的模式默认为一组众所周知的内部IP地址,如 10.*.*.*192.168.*.* ,因此如果您的代理不在其中一个上,则需要明确配置它,例如

    server.tomcat.internal-proxies=172\\.17\\.\\d{1,3}\\.\\d{1,3}|127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}
    

    (使用属性文件格式,这意味着您必须双重转义反斜杠) .

    如果设置,您可以看到 RemoteIpValve 中发生的情况

    logging.level.org.apache.catalina.valves.RemoteIpValve=DEBUG
    

    或在其中设置断点 .

  • 0

    此问题的典型解决方案是让代理处理任何所需的重写 . 例如,在Apache中,您可以使用rewrite_module和/或headers_module来更正标头 . 另一个例子,Nginx在配置上游服务器后自动为您处理此问题和其他类似情况 .

    回应评论:

    remote_ip_header和protocol_header spring 引导配置值是什么?

    让我们暂时忘记Spring Boot . Tomcat是嵌入式servlet容器,它具有一个名为RemoteIpValve的阀门 . 这个阀门是Apache remotip_module的一个端口 . 这个阀门的主要目的是将"useragent which initiated the request as the originating useragent"视为"the purposes of authorization and logging" . 为了使用这种阀门,需要对其进行配置 .

    请找到有关此阀门的更多信息here .

    Spring Boot方便地通过server.tomcat.remote_ip_header和server.tomcat.protocol_header属性通过application.properties配置此阀门 .

  • 17

    我使用haproxy作为负载均衡器使用以下配置完全相同的情况,这对我来说很有用 . 唯一的问题是客户端IP位于 request.getRemoteAddr() 而不是 "X-Forwarded-For" 标头中

    frontend www
      bind *:80
      bind *:443 ssl crt crt_path
      redirect scheme https if !{ ssl_fc }
      mode http
      default_backend servers
    
    backend servers
      mode http
      balance roundrobin
      option forwardfor
      server S1 host1:port1 check
      server S2 host2:port2 check
      http-request set-header X-Forwarded-Port %[dst_port]
      http-request add-header X-Forwarded-Proto https if { ssl_fc }
    

    在application.properties中:

    server.use-forward-headers=true
    
  • 2

    你试过设置吗?

    server.context-path=/appname
    

    在Spring Boot?

  • 1

    尝试设置重写规则,如:https://proxyserver:4433/appname >> forward >> http://appserver:8080/appname

    然后将应用程序上下文设置为“appname”server.context-path = / appname

    所以在本地你可以运行http://appserver:8080/appname并通过反向代理通过https://proxyserver:4433/appname访问

    由于我使用的是JBOSS,因此更改了standalone.xmJBoss的:

    <http-listener name="default" socket-binding="http" redirect-socket="https" proxy-address-forwarding="true" enable-http2="true"/>
    

    Tomcat将具有类似的配置,以通知Tomcat(proxy-address-forwarding =“true”)以尊重代理转发地址 .

相关问题