Nginx通过错误页面重定向传递HTTP头

Nginx通过错误页面重定向传递HTTP头,nginx,Nginx,tl:dr,如果使用nginx error_page指令重定向请求,如何确保通过此重定向传递自定义头 我目前正在实现一个系统,其中nginx针对LDAP服务器进行身份验证,并充当反向代理。基于此 它的工作方式是,它有一个包罗万象的服务器块,将请求发送到另一个端口上运行的身份验证页面,这会根据cookie的内容发回403或200。如果这是403,那么用户将被发送到登录页面,如果是200,则发送到其目的地 nginx conf的示例如下: location / { auth_request

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

我目前正在实现一个系统,其中nginx针对LDAP服务器进行身份验证,并充当反向代理。基于此 它的工作方式是,它有一个包罗万象的服务器块,将请求发送到另一个端口上运行的身份验证页面,这会根据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没有转发它。我尝试在error\u page指令之前包含行“proxy\u set\u header X-authenticationfail$http\u X\u authenticationfail;”、“add\u header X-authenticationfail”test“always;”,但这没有效果。我也在同一个位置尝试了“proxy\u pass\u header X-authenticationfail”,但也失败了

服务器块设置了“下划线在上的\u头”和“代理通过上的\u请求上的\u头”。在登录块中,放置“proxy\u set\u header X-authenticationfail”testvalue“;”将值传递到登录python代码,然后从那里返回到浏览器


谢谢你走了这么远

根据您的描述,任务是在一个位置保留来自
auth_请求
响应的头,然后将此头传递到另一个位置的下一个上游

在发出请求的位置内,可以使用
$sent\u http.
变量访问任何响应的标题。这里的问题是Nginx非常高效。如果您设法逃出一个位置,即进行内部重定向,Nginx将决定您将要发出另一个请求、提供一个静态文件或执行其他操作。因此,来自上一个请求的任何数据现在都被认为是无关的,并被驳回以释放一些内存。换句话说,
$sent\uhttp\uhttp
变量被附加到某个位置,一旦您离开该位置,它们就会停止工作

然而,有一种方法可以通过对保存感兴趣的值的内存区域进行另一次引用来保留其中一些变量。这是可能的,因为正如前面提到的,Nginx是内存高效的。如果您将一个变量的值分配给另一个varialbe,web服务器将不会复制源变量的值,除非确实需要。相反,它将使用内存中的地址设置新变量的内部指针,源变量的值保存在内存中

因此,如果您分配一个值为
$sent\u http
的新变量,将有两个对存储响应头的内存区域的引用。您的新变量将保持此内存区域不被擦除,因为与大多数只在特定位置工作的内置变量不同,用户定义的变量附加到服务器上下文

因此,为了解决您的问题,您需要定义一个新变量,并将其赋值为
$sent\u http\u x\u authenticationfail

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

幸运的是,Nginx中有一个特殊的指令,允许使用
auth\u request
的结果分配一个新变量。这个指令是。将其与
proxy\u set\u 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\u reason
$sent\u http\u x\u authenticationfail
现在都指向相同的内存区域,您可以在您的
登录
位置中使用这些变量中的任何一个,并获得相同的结果。

只需在您的
/login
位置中添加
代理集\u头X-Authenticationfail$sent\u http\u X\u Authenticationfail
即可,但仍然没有成功,另外添加
身份验证请求设置$falure\u原因$sent\u http\u X\u Authenticationfail右下方
身份验证请求
。你甚至不必在任何地方使用
$falure\u reason
。不知何故,这一行的存在将使我的第一个解决方案非常有效,你想把它写下来作为一个答案,这样我就可以给你信用了吗?