如何覆盖 401 上的 WWW-Authenticate

Mic*_*ung 2 nginx nginx-reverse-proxy nginx-config

我有一项返回的服务:

WWW-Authenticate: Negotiate, Basic realm="TM1"
Run Code Online (Sandbox Code Playgroud)

由于这不适用于 libcurl,我尝试使用 nginx 来修改这些标头,如下所示:

WWW-Authenticate: Negotiate
WWW-Authenticate: Basic realm="TM1"
Run Code Online (Sandbox Code Playgroud)

我失败的尝试#1:

http {
    proxy_intercept_errors on;

    server {
        listen       10103;
        server_name  localhost;

        location / {
            proxy_pass https://tm1server:10103;
            proxy_intercept_errors on;
            proxy_hide_header WWW-Authenticate;

            add_header "Status is" "${status}" always;
            if ($status = 401) {
                add_header WWW-Authenticate 'Basic realm="TM1"' always;
                add_header WWW-Authenticate 'Negotiate' always;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

$ curl -sv http://localhost:10103/api/v1/Configuration
*   Trying 127.0.0.1:10103...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 10103 (#0)
> GET /api/v1/Configuration HTTP/1.1
> Host: localhost:10103
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.18.0
< Date: Tue, 09 Jun 2020 14:09:14 GMT
< Content-Type: text/plain
< Content-Length: 0
< Connection: keep-alive
< OData-Version: 4.0
< Set-Cookie: TM1SessionId=rc6xBs4_ZtKRTA3IyIBRIA; Path=/api/; HttpOnly; Secure
< Status is: 401
<
* Connection #0 to host localhost left intact
Run Code Online (Sandbox Code Playgroud)

为什么不起作用if ($status = 401)

我失败的尝试#2(因为无论如何,如果是邪恶的):

http {
    proxy_intercept_errors on;

    server {
        listen       10103;
        server_name  localhost;

        location / {
            proxy_pass https://tm1server:10103;
            proxy_intercept_errors on;
            proxy_hide_header WWW-Authenticate;

            error_page 401 = @401;
        }

        location @401 {
            proxy_hide_header WWW-Authenticate;
            # Preferably, only set those available in $http_www_authenticate
            add_header WWW-Authenticate 'Basic realm="TM1"' always;
            add_header WWW-Authenticate 'Negotiate' always;
            return 401 "Authentication required";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

$ curl -sv http://localhost:10103/api/v1/Configuration
Authentication required*   Trying 127.0.0.1:10103...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 10103 (#0)
> GET /api/v1/Configuration HTTP/1.1
> Host: localhost:10103
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.18.0
< Date: Tue, 09 Jun 2020 14:10:16 GMT
< Content-Type: text/plain
< Content-Length: 23
< Connection: keep-alive
< WWW-Authenticate: Negotiate, Basic realm="TM1"
< WWW-Authenticate: Basic realm="TM1"
< WWW-Authenticate: Negotiate
<
{ [23 bytes data]
* Connection #0 to host localhost left intact
Run Code Online (Sandbox Code Playgroud)

为什么不起作用proxy_hide_header(不管我在哪里设置)

或者是更好的方法?

Iva*_*sky 6

您的第一个问题的答案可以在您提供的 if-is-evil 链接下找到(请参阅location该页面上示例配置的第一个块)。我没有回答你的第二个问题(proxy_hide_header在这种情况下不起作用也让我感到惊讶),但由于上游标头在第一个配置中被隐藏,你可以尝试这个:

http {
    map $status $auth1 {
        401    'Basic realm="TM1"';
    }
    map $status $auth2 {
        401    'Negotiate';
    }

    server {
        listen       10103;
        server_name  localhost;

        location / {
            proxy_pass https://tm1server:10103;
            proxy_intercept_errors on;
            proxy_hide_header WWW-Authenticate;
            add_header WWW-Authenticate $auth1 always;
            add_header WWW-Authenticate $auth2 always;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)