Nginx通过error_page重定向传递HTTP标头

时间:2016-12-15 11:34:32

标签: nginx

tl:dr,如果使用nginx error_page指令重定向请求,如何确保使用此重定向传递自定义标头。

我目前正在实施一个系统,其中nginx针对LDAP服务器进行身份验证,并充当反向代理。它基于此https://www.nginx.com/blog/nginx-plus-authenticate-users/ 它的工作方式是,它有一个包含所有服务器块,它将请求发送到另一个端口上运行的身份验证页面,根据cookie的内容发送回403或200。如果这是403,则用户被发送到登录页面,如果200到目的地。

示例nginx conf在这里:

location / {
    auth_request /auth-proxy;

    # redirect 401 to login form
    error_page 401 =200 /login;

    proxy_pass http://backend/;
}

location /login {
    proxy_pass http://backend/login;
    # Login service returns a redirect to the original URI
    # and sets the cookie for the ldap-auth daemon
    proxy_set_header X-Target $request_uri;
}

location = /auth-proxy {
    internal;

    # The ldap-auth daemon listens on port 8888, as set
    # in nginx-ldap-auth-daemon.py.
    # Change the IP address if the daemon is not running on
    # the same host as NGINX/NGINX Plus.
    proxy_pass http://127.0.0.1:8888;
}

问题是,我做了一个更改,使得身份验证部分超时并返回403代码,无论cookie是否有效。但是我想让用户知道登录页面上发生了这种情况,因此python身份验证代码设置了X-authenticationfail标头,其中包含错误值。

我已经通过使用curl将超时cookie发送到身份验证代码来检查此工作,然后阅读标题。但是,当调用登录python代码时,此标头已消失。我认为这是由于nginx没有转发它。我试图将行" proxy_set_header X-authenticationfail $ http_x_authenticationfail;"," add_header X-authenticationfail" test"总是;"在error_page指令之前,但这没有任何效果。我还尝试过#se; proxy_pass_header X-authenticationfail"在同一地点,但这也失败了。

服务器块上有" underscores_in_headers"设置," proxy_pass_request_headers on"组。在登录块中,放置" proxy_set_header X-authenticationfail" testvalue";"得到登录python代码的值,然后从那里返回浏览器。

感谢您走到这一步!

1 个答案:

答案 0 :(得分:1)

根据您的描述,任务是在一个位置保留auth_request响应中的标头,然后将此标头传递到另一个位置的下一个上游。

可以使用{/ 1}}变量请求所在的位置访问任何响应的标头。这里的问题是Nginx的内存效率非常高。如果您以某种方式设法逃离某个位置,即进行内部重定向,Nginx会决定您要发出另一个请求,提供静态文件或执行其他操作。因此,现在认为来自先前请求的任何数据都是无关紧要的,并且为了释放一些内存而被解雇。换句话说,$sent_http_<header name>变量会附加到某个位置,并且只要您离开该位置就会停止工作。

但是,有一种方法可以通过对保存感兴趣值的内存区域进行另一次引用来保留其中一些变量。这是可能的,因为如前所述,Nginx具有内存效率。如果为变量分配另一个变量的值,则除非确实需要,否则Web服务器不会复制源变量的值。相反,它将使用内存中的地址设置新变量的内部指针,其中保留源变量的值。

因此,如果您分配一个值为$sent_http_<header name>的新变量,则会有两个对存储响应头的内存区域的引用。并且您的新变量将使这个内存区域不被擦除,因为与大多数仅在特定位置内工作的内置变量不同,用户定义的变量附加到服务器上下文。

因此,为了解决您的问题,您需要定义一个新变量并为其赋值$sent_http_<header name>

第一个明显的选择是使用$sent_http_x_authenticationfail指令。但是它不起作用,因为set在请求处理的早期阶段被调用,在发送任何请求并收到任何响应之前。

幸运的是,Nginx中有一个特殊的指令,它允许使用set的结果分配一个新的变量。这个指令是auth_request_set。将它与auth_request相结合,您将得到您想要的东西:

proxy_set_header

请注意,由于location / { auth_request /auth-proxy; # Step 1: force Nginx to preserve the response header auth_request_set $falure_reason $sent_http_x_authenticationfail; error_page 401 =200 /login; proxy_pass http://backend/; } location /login { proxy_pass http://backend/login; proxy_set_header X-Target $request_uri; # Step 2: pass the preserved header value to the next upstream proxy_set_header X-Authenticationfail $sent_http_x_authenticationfail; } location = /auth-proxy { internal; proxy_pass http://127.0.0.1:8888; } $falure_reason现在都指向相同的内存区域,因此您可以在$sent_http_x_authenticationfail位置使用这些变量中的任何一个,但结果相同。