oauth2-client在Nginx代理后遇到的问题和解决方案

oauth2-client在Nginx代理后遇到的问题和解决方案

OAuth2 Client在实际运用过程中遇到的问题

服务程序集成了OAuth2-Client,以便于用户能够方便集成到支持OAuth2第三方登录的自有业务系统中。开发完成后,本地测试、或者直连服务程序,都没有问题。但凡放到线上环境,经过了nginx 转发后,我们的服务程序OAuth登录永远是以失败告终。

现象如下:

访问需要授权的接口时 https://blog.95id.com:4005/user_attr,期望是跳转到授权服务器 github.com进行登录授权,但实际都是跳转到``http://blog.95id.com/login`

因为当时直接用服务程序的端口没问题,就将解决思路放在了nginx 转发过程上。

当时线上环境路由规则类似于:

第一层:nginx1 4005 (ssl、负载均配置在这)

第二层:nginx2 4005

第三层:oauth2-client 8082

再看nginx 的配置,第一层nginx 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
server {
listen 4005;
server_name blog.95id.com;
ssl on;
ssl_certificate xxx.crt
......

location / {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header remote_addr $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://xxxserver_4005;
......

upstream xxxserver_4005 {
server {nginx2-ip}:4005;
}

第二层nginx 的配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 4005;
server_name 0.0.0.0;
port_in_redirect off;
location / {
add_header Cache-Control no-store;
proxy_pass http://127.0.0.1:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

因为当时nginx配置比较复杂,怎么调oauth的配置都不对,就对问题进行一个个简化拆分,一个问题一个问题的解决

场景一:nginx 80 代理 oauth-client 8082

有了nginx ,就会出现异常,那么从最简单的场景开始测试。

程序配置:

1
server.port=8082

nginx 配置:

nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name blog.95id.com;
port_in_redirect off;
location / {
add_header Cache-Control no-store;
proxy_pass http://127.0.0.1:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

查看请求重定向详情

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
curl -Lv http://blog.95id.com/user_attr

* 打印信息中有删减,保留跳转的信息

* Connected to blog.95id.com (212.64.15.210) port 80 (#0)
> GET /user_attr HTTP/1.1
> Host: blog.95id.com

< HTTP/1.1 302
< Server: nginx/1.12.2
< Location: http://blog.95id.com/login
< Cache-Control: no-store
> GET /login HTTP/1.1
> Host: blog.95id.com

< HTTP/1.1 302
< Server: nginx/1.12.2
< Date: Tue, 14 Jan 2020 02:18:33 GMT
< Location: https://github.com/login/oauth/authorize?client_id=da2eedb7fbffa926eeab&redirect_uri=http://blog.95id.com/login&response_type=code&state=ApP8wq
> GET /login/oauth/authorize?client_id=da2eedb7fbffa926eeab&redirect_uri=http://blog.95id.com/login&response_type=code&state=ApP8wq HTTP/1.1
> Host: github.com
.......

< HTTP/1.1 302 Found
< Date: Tue, 14 Jan 2020 02:18:34 GMT
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Server: GitHub.com
< Status: 302 Found
< Location: https://github.com/login?client_id=da2eedb7fbffa926eeab&return_to=%2Flogin%2Foauth%2Fauthorize%3Fclient_id%3Dda2eedb7fbffa926eeab%26redirect_uri%3Dhttp%253A%252F%252Fblog.95id.com%252Flogin%26response_type%3Dcode%26state%3DApP8wq
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="dns-prefetch" href="https://github.githubassets.com">

跳转一切正常

场景二: 非80端口nginx 代理 oauth-client 8082

用 4005 端口 代理 oauth-client的8082

nginx配置

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 4005;
server_name blog.95id.com;
port_in_redirect off;
location / {
add_header Cache-Control no-store;
proxy_pass http://127.0.0.1:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

这时候打印请求详情

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
curl -Lv http://blog.95id.com:4005/user_attr


# 请求 blog.95id.com:4005/user_attr
* Connected to blog.95id.com (212.64.15.210) port 4005 (#0)
> GET /user_attr HTTP/1.1
> Host: blog.95id.com:4005

# 重定向 blog.95id.com/login
< HTTP/1.1 302
< Server: nginx/1.12.2
< Date: Tue, 14 Jan 2020 02:29:06 GMT
< Location: http://blog.95id.com/login
* Connected to blog.95id.com (212.64.15.210) port 80 (#1)
> GET /login HTTP/1.1
> Host: blog.95id.com
> User-Agent: curl/7.54.0
> Accept: */*

# 无法访问 blog.95id.com/login,缺少port,预期port 为 4005
< HTTP/1.1 502 Bad Gateway
< Server: nginx/1.12.2

如果把 nginx 的port_in_redirect 配置设置为 on,结果也是一样的,这个跳转是oauth-client程序内 spring-security-oauth2 自动做的跳转,也就是spring-security-oauth2 未能正常拿到4005 这个端口

再来看应用程序日志(DEBUG模式下)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2020-01-14 10:58:43.388 DEBUG 1918 --- [http-nio-8082-exec-7] o.a.tomcat.util.net.SocketWrapperBase    : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@5fc01a1e:org.apache.tomcat.util.net.NioChannel@58241aaa:java.nio.channels.SocketChannel[connected local=/127.0.0.1:8082 remote=/127.0.0.1:43746]], Read from buffer: [0]
2020-01-14 10:58:43.388 DEBUG 1918 --- [http-nio-8082-exec-7] o.a.coyote.http11.Http11InputBuffer : Received [GET /user_attr HTTP/1.0
Host: blog.95id.com
X-Real-IP: 208.76.1.123
X-Forwarded-For: 208.76.1.123
Connection: close
User-Agent: curl/7.54.0
Accept: */*
]
...
2020-01-14 10:58:43.391 DEBUG 1918 --- [http-nio-8082-exec-7] o.s.s.w.a.i.FilterSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@9055e4a6: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
...
org.springframework.security.access.AccessDeniedException: Access is denied
...
2020-01-14 10:58:43.393 DEBUG 1918 --- [http-nio-8082-exec-7] o.s.s.w.s.HttpSessionRequestCache : DefaultSavedRequest added to Session: DefaultSavedRequest[http://blog.95id.com/user_attr]
...
2020-01-14 10:58:43.394 DEBUG 1918 --- [http-nio-8082-exec-7] s.w.a.DelegatingAuthenticationEntryPoint : No match found. Using default entry point org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint@1df284b4
2020-01-14 10:58:43.394 DEBUG 1918 --- [http-nio-8082-exec-7] o.s.s.web.DefaultRedirectStrategy : Redirecting to 'http://blog.95id.com/login'

从打印的日志看,因为user_attr需要授权允许,所以跳转到 /login。但是当时spring-security已经拿不到4005端口了

打印的request信息也证实了,4005丢失不见了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"header": [
"host::blog.95id.com",
"x-real-ip::208.76.1.123",
"x-forwarded-for::208.76.1.123",
....
],
"info": [
"method:GET",
"uri:/print_request",
"url:http://blog.95id.com/print_request",
"context_path:",
"IP:127.0.0.1",
"ServerPort:80",
"LocalPort:8082",
"RemotePort:46856"
]
}

经过查找几次尝试,解决方法是在nginx -server 中加入配置:

1
proxy_set_header   Host             $host:$server_port;

这时request信息中,ServerPort = 4005

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

{
"header": [
"host::blog.95id.com:4005",
"x-real-ip::208.76.1.123",
"x-forwarded-for::208.76.1.123",
....
],
"info": [
"method:GET",
"uri:/print_request",
"url:http://blog.95id.com:4005/print_request",
"context_path:",
"IP:127.0.0.1",
"ServerPort:4005",
"LocalPort:8082",
"RemotePort:53908"
]
}

该方案解决了端口丢失的问题,接着解决 https 变成 http的问题

场景三:HTTS 443端口 代理 oauth-client 8082

443 是 ssl的默认端口,场景二修改监听端口,再加上 ssl的配置,nginx配置如下:

nginx配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
server {
listen 443;
ssl on;
server_name blog.95id.com;
index index.html index.htm index.php;
add_header Timing-Allow-Origin "*";
add_header Access-Control-Allow-Origin "*";
port_in_redirect off;
ssl_certificate /data/apps/wwwroot/Nginx/1_blog.95id.com_bundle.crt;
ssl_certificate_key /data/apps/wwwroot/Nginx/2_blog.95id.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
add_header Cache-Control no-store;
proxy_pass http://127.0.0.1:8082;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

问题现象:

访问:https://blog.95id.com/user_attr

被redirect to :http://blog.95id.com/login

浏览器报 400异常(因为重定向的是http,没配80端口)

1
2
400 Bad Request
The plain HTTP request was sent to HTTPS port

curl 超时(因为重定向的是http,没配80端口)

1
2
3
4
[root@VM_0_17_centos oauth]# curl -Lv https://blog.95id.com/user_attr
* About to connect() to blog.95id.com port 80 (#0)
* Trying 212.64.15.210...
^C

这样配置发现 https 被重定向到 http,并且htts默认的443端口,变成了http的默认端口80

解决方案:

在oauth-client 配置文件中

1
2
3
4
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=X-Forwarded-Proto
#server.tomcat.protocol-header-https-value=https
server.use-forward-headers=true

nginx 配置中加入

1
proxy_set_header   X-Forwarded-Proto   $scheme;

测试可行

最后nginx配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server {
listen 443;
ssl on;
server_name blog.95id.com;
index index.html index.htm index.php;
add_header Timing-Allow-Origin "*";
add_header Access-Control-Allow-Origin "*";
port_in_redirect off;
ssl_certificate /data/apps/wwwroot/Nginx/1_blog.95id.com_bundle.crt;
ssl_certificate_key /data/apps/wwwroot/Nginx/2_blog.95id.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
add_header Cache-Control no-store;
proxy_pass http://127.0.0.1:8082;
#proxy_set_header Host $host;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

场景四 HTTPS 非443端口代理oauth-client 8082

开启ssl,用4005端口代替默认端口443。并且沿用场景二的方案,便于将端口同时带过来,可是还是出问题了

问题现象

沿用场景三的解决方案,并且带了场景二的方案,发现还是无法重定向到oauth2-server进行登录

访问:https://blog.95id.com:4005/user_attr

最后被重定向到:https://blog.95id.com/login

nginx 配置和场景三类似,只是修改了端口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server {
listen 4005;
ssl on;
server_name blog.95id.com;
index index.html index.htm index.php;
add_header Timing-Allow-Origin "*";
add_header Access-Control-Allow-Origin "*";
port_in_redirect off;
ssl_certificate /data/apps/wwwroot/Nginx/1_blog.95id.com_bundle.crt;
ssl_certificate_key /data/apps/wwwroot/Nginx/2_blog.95id.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
add_header Cache-Control no-store;
proxy_pass http://127.0.0.1:8082;
#proxy_set_header Host $host;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

https 是被带过来了,但是 端口4005丢失了,浏览器报不是私密链接(因为443端口没配ssl),curl 报连接超时 443端口没做转发

在场景二中配置的

1
proxy_set_header   Host              $host:$server_port;

也在其中,但是还是未生效

解决方案

在nginx 配置中增加

1
proxy_set_header   X-Forwarded-Port    $server_port;

在oauth2-client 的配置文件application.properties中添加:

application.properties
1
server.tomcat.port-header=X-Forwarded-Port

改动后的nginx 配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
server {
listen 4005;
ssl off;
server_name blog.95id.com;
index index.html index.htm index.php;
add_header Timing-Allow-Origin "*";
add_header Access-Control-Allow-Origin "*";
port_in_redirect off;
ssl_certificate /data/apps/wwwroot/Nginx/1_blog.95id.com_bundle.crt;
ssl_certificate_key /data/apps/wwwroot/Nginx/2_blog.95id.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
add_header Cache-Control no-store;
proxy_pass http://127.0.0.1:8082;
#proxy_set_header Host $host;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
}
}

oauth-client 配置

1
2
3
4
5
6
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=X-Forwarded-Proto
server.use-forward-headers=true
server.tomcat.port-header=X-Forwarded-Port

server.port=8082

其他尝试

测试发现X-Forwarded-Port这个配置是否能可以解决端口丢失的问题,那么是否能用来解决场景二的问题?回到场景二的配置

1
2
3
4
5
#关闭ssl 
ssl off;
# Host 设置为不带port ,而是通过X-Forwarded-Port 传递
proxy_set_header Host $host;
#proxy_set_header Host $host:$server_port;

oauth-client 配置保持和场景三方案一样

测试的nginx 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
server {
listen 4005;
ssl off;
server_name blog.95id.com;
index index.html index.htm index.php;
add_header Timing-Allow-Origin "*";
add_header Access-Control-Allow-Origin "*";
port_in_redirect off;
ssl_certificate /data/apps/wwwroot/Nginx/1_blog.95id.com_bundle.crt;
ssl_certificate_key /data/apps/wwwroot/Nginx/2_blog.95id.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
add_header Cache-Control no-store;
proxy_pass http://127.0.0.1:8082;
proxy_set_header Host $host;
#proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
}
}

测试通过,也就是 proxy_set_header Host $host:$server_port;可以通过X-Forwarded-Port方案替代

场景五 双层nginx 转发 https协议头 port丢失

上述场景都是单层的nginx 环境,如果用上述配置放到线上(也就是开篇描述的现象),还是出了问题。

但是单层nginx的解决了,多层的还会远吗?而且经过这么多场景的模拟测试,该问题的本质也逐渐明了,就是nginx 在转发request过程中https和port丢失的问题,多层的情况就是要解决第一层nginx 到最内层的nginx 中一些参数的传递问题

第一层:nginx1 4005 (ssl、负载均配置在这)

第二层:nginx2 4005

第三层:oauth2-client 8082

问题现象

访问:https://blog.95id.com:4005/user_attr

最后被重定向到:http://blog.95id.com/login

那么经过这么多场景,能够很清晰的定位问题: 协议头和port在nginx 代理过程中丢失,最有可能是第一层nginx 到 第二层nginx 过程中丢失。

另外在最外层nginx 配置了场景4nginx的配置,port不丢失了,但是最终还是重定向到了 http://blog.95id.com:4005/login,https丢了

解决方案

两种解决方案:

两个方案均需要在外层的nginx 上将https 往下层传,所以都需要:

1
2
3
4
5
proxy_set_header   Host                $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;

如果是多层,就是要将 schema 和 port 层层往下传

1)方案一:强制使用https

如果nginx服务并没有直接面向最终用户,而是在某些负载均衡/cdn后面,并且ssl证书是在这些负载均衡/cdn上面配置的,那么有可能会导致nginx无法正确获取客户端所使用的协议,从而导致无法将客户端使用的协议传递给最后面的应用程序。在这种情况下,可以修改nginx配置,强制通知服务使用https协议,也就是不使用 $scheme 变量,而是写死 https。

1
2
#proxy_set_header   X-Forwarded-Proto   $scheme;
proxy_set_header X-Forwarded-Proto https;

2) 方案二:利用$http_x_forwarded_proto变量

除了最外层的nginx ,其余层的nginx在的http 内配置:

1
2
3
4
5
6
map $http_x_forwarded_proto $thescheme{
default $http_x_forwarded_proto;
'' $scheme;
}
# $http_x_forwarded_proto 不为空 $thescheme 取 $http_x_forwarded_proto
# $http_x_forwarded_proto 为空 $thescheme 取$scheme

在转发服务的nginx -server 中配置:

1
2
#proxy_set_header   X-Forwarded-Proto   $scheme;
proxy_set_header X-Forwarded-Proto $thescheme;

Bingo !尝试大几十遍终于都可以了

终极配置方案

上述这些场景导致OAuth2-Client 无法正常使用,本质原因还是因为 request的schema 和port 无法下传到 应用程序导致的。如果java应用程序能正常拿到,就不存在这些问题,所以只需要解决,request从nginx到client,不丢失相关信息即可

通过这些配置,发现后面方案是可以兼容解决前面的场景,所以这里可以给个最终的配置方案

不管是 默认端口代理,还是开启Https ,还是层层代理,这个配置都可以使OAuth2Client 生效

1)在应用程序的主配置文件中加入:

1
2
3
4
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=X-Forwarded-Proto
server.use-forward-headers=true
server.tomcat.port-header=X-Forwarded-Port

2)在nginx 配置中,http模块下,加一个map设置thescheme参数用来传递scheme,在代理服务的server配置中,加入header相关配置(proxy_set_header 开头):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
http {
map $http_x_forwarded_proto $thescheme{
default $http_x_forwarded_proto;
'' $scheme;
}
......
server {
listen 4005;
server_name 0.0.0.0;

location / {
proxy_pass http://127.0.0.1:8082;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $thescheme;
proxy_set_header X-Forwarded-Port $server_port;
}
......
}

3)在springboot应用程序中加入如下配置

1
2
3
4
server.tomcat.remote-ip-header=x-forwarded-for
server.tomcat.protocol-header=X-Forwarded-Proto
server.use-forward-headers=true
server.tomcat.port-header=X-Forwarded-Port

如果是非内嵌的tomcat , 则需要修改tomcat 的配置(无tomcat,未测试)

1
2
3
4
5
<!-- 放在<Valve className="org.apache.catalina.valves.AccessLogValve">的后面(同级关系)-->
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="X-Forwarded-For"
protocolHeader="X-Forwarded-Proto"
portHeader="X-Forwarded-Port"/>

测试用的OAuth2-Client源码 和 nginx 最终配置方案可以见 https://github.com/ifengkou/oauth2-client-157

补习 springboot 下 HTTP HEADER 参数知识

  • server.tomcat.port-header 设定http header使用的,用来覆盖原来port的value.
  • server.tomcat.protocol-header 设定Header包含的协议,通常是 X-Forwarded-Proto,如果remoteIpHeader有值,则将设置为RemoteIpValve.
  • server.tomcat.protocol-header-https-value 设定使用SSL的header的值,默认https.
  • server.tomcat.remote-ip-header 设定remote IP的header,如果remoteIpHeader有值,则设置为RemoteIpValve
  • server.use-forward-headers=true该配置将指示tomcat从HTTP头信息中去获取协议信息(而非从HttpServletRequest中获取),同时,如果你的应用还用到了spring-security则也无需再配置。

补习Java 程序获得相关请求信息

可以具体见Oauth2-client 项目中 Oauth2Client157Application文件内的 printRequest方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 List<String> headerInfo = new ArrayList<>();
//获得所有的头的名称
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()){
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
headerInfo.add(headerName+"::"+headerValue);
}
List<String> urlInfo = new ArrayList<>();
urlInfo.add("method:" + request.getMethod());
urlInfo.add("uri:" + request.getRequestURI());
urlInfo.add("url:" + request.getRequestURL());
urlInfo.add("ServerPort:" + request.getServerPort());
urlInfo.add("LocalPort:" + request.getLocalPort());
urlInfo.add("serverName:"+request.getServerName());
urlInfo.add("schema:"+request.getScheme());

访问:https://blog.95id.com:4005/print_request

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"header": [
"host::blog.95id.com",
"x-real-ip::213.123.1.2",
"x-forwarded-proto::https",
"x-forwarded-port::4005",
......
],
"info": [
"method:GET",
"uri:/print_request",
"url:https://blog.95id.com:4005/print_request",
"context_path:",
"IP:213.123.1.2",
"ServerPort:4005",
"LocalPort:8082",
"RemotePort:37516",
"serverName:blog.95id.com",
"schema:https"
]
}

补习 Nginx 参数配置

nginx ssl 证书配置

1
2
3
4
5
6
7
8
ssl on;
ssl_certificate /data/apps/wwwroot/Nginx/1_blog.95id.com_bundle.crt;
ssl_certificate_key /data/apps/wwwroot/Nginx/2_blog.95id.com.key;
ssl_session_timeout 5m;
ssl_session_cache shared:SSL:10m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;

配置自动获取协议方式

通过这种方式配置,客户端可以使用http或者https协议,应用服务能够自动获取客户端使用的协议。

配置nginx 反向代理 proxy_set_header 。 在server里面,增加下面的配置:

1
2
3
4
5
6
7
8
9
server {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header x-wiz-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
...
}

如果您的nginx有多层,那么,您可能还需要额外的配置: 在http 模块中加入以下配置:

1
2
3
4
map $http_x_forwarded_proto $thescheme{
default $http_x_forwarded_proto;
'' $scheme;
}

然后在server模块(或者http模块)里面,将前面配置中的proxy_set_header X-Forwarded-Proto $scheme;,替换为下面的代码:

1
proxy_set_header  X-Forwarded-Proto  $thescheme;

如果您的nginx服务,并没有直接面向最终用户,而是在某些负载均衡/cdn后面,并且您的ssl证书是在这些负载均衡/cdn上面配置的,那么有可能会导致nginx无法正确获取客户端所使用的协议,这时可以强制https

1
proxy_set_header X-Forwarded-Proto "https";

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×