我们有一个Spring Boot(Spring MVC)应用程序,在Apache SSL代理后面的专用appserver上嵌入了Tomcat。
代理服务器上的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
但尚未成功。
我正在尝试应用此解决方案: 59.8 Use Tomcat behind a front-end proxy server
我们在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
。
我们需要做些什么来使这个场景有效吗?
另外,我担心" / appname"部分在代理URL中。在appserver上,应用程序的根源是" /"。 Spring应该如何指示" / appname"应该包含在通过代理发送回客户端的所有URL中吗?
答案 0 :(得分:23)
I had the same problem the other day. After some debugging of Spring Boot 1.3 I found the following solution.
1. You have to setup the headers on your Apache proxy:
<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. You have to tell your Spring Boot app to use these headers. So put the following line in your application.properties (or any other place where Spring Boots understands properties):
server.use-forward-headers=true
If you do these two things correctly, every redirect your application sends will not go to http://127.0.0.1:8080/[path] but automatically to https://www.myapp.com/[path]
Update 1. The documentation about this topic is here. You should read it at least to be aware of the property server.tomcat.internal-proxies
which defines the range of IP-addresses for proxy servers that can be trusted.
答案 1 :(得分:4)
您的代理看起来很好,后端应用也是如此,但它似乎没有看到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
或在其中设置断点。
答案 2 :(得分:2)
此问题的典型解决方案是让代理处理任何所需的重写。例如,在Apache中,您可以使用rewrite_module和/或headers_module来更正标头。作为另一个例子,Nginx在配置上游服务器后自动为您处理此类和其他类似情况。
回应评论:
remote_ip_header和protocol_header弹簧启动配置值是什么?
让我们暂时忘记Spring Boot。 Tomcat是嵌入式servlet容器,它具有一个名为RemoteIpValve的阀门。该阀门是Apache remotip_module的一个端口。该阀门的主要目的是将发起请求的&#34;使用者视为原始使用者&#34;为了#34;授权和记录的目的&#34;。为了使用这种阀门,需要对其进行配置。
请找到有关此阀门的更多信息here。
Spring Boot方便地通过server.tomcat.remote_ip_header和server.tomcat.protocol_header属性通过application.properties配置此阀门。
答案 3 :(得分:1)
我使用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
答案 4 :(得分:0)
您是否尝试过设置
server.context-path=/appname
在Spring Boot中?
答案 5 :(得分:0)
尝试像这样设置重写规则: https://proxyserver:4433/appname >>转发>> http://appserver:8080/appname
然后将您的应用程序上下文设置为“ appname” server.context-path = / appname
因此,在本地您可以通过http://appserver:8080/appname运行,并通过反向代理通过https://proxyserver:4433/appname访问
由于我使用的是JBOSS,因此更改了jboss的standalone.xm:
<http-listener name="default" socket-binding="http" redirect-socket="https" proxy-address-forwarding="true" enable-http2="true"/>
Tomcat将具有类似的配置,以通知Tomcat(proxy-address-forwarding =“ true”)遵守代理转发地址。
答案 6 :(得分:0)
有几个与此相关的属性可以配置。
application.yaml
示例:
server:
forward-headers-strategy: native
tomcat:
use-relative-redirects: true
protocol-header: x-forwarded-proto
remote-ip-header: x-forwarded-for
设置server.forward-headers-strategy: native
代替不推荐使用的server.use-forward-headers:true
答案 7 :(得分:0)
server.use-forward-headers=true
对我不起作用,遇到了一个奇怪的问题,即 X-Forwarded-For
标头未始终填充到 HttpServletRequest
。
最终使用了 ForwardedHeaderFilter
:https://stackoverflow.com/a/51500554/986942。
最重要的是,确保负载平衡器(代理)正确提供以下标头:
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;