Nginx-解码URL查询参数并将其作为请求头转发

Nginx-解码URL查询参数并将其作为请求头转发,nginx,basic-authentication,urlencode,url-encoding,Nginx,Basic Authentication,Urlencode,Url Encoding,我需要发送一些基本的身份验证凭据。用户:以查询参数es的形式传递给nginx。http://example.com?BASIC_AUTH=dXNlcjpwYXNz 并且能够以更常见的授权方式(基本的dXNlcjpwYXNz头格式)将它们转发到代理后面的目标服务器 我已经能够用正则表达式检索编码的auth字符串的值。问题是,该值通常可能包含一些需要在URL中进行百分比编码的字符。锿。用户:通过!->?BASIC_AUTH=dXNlcjpwYXNzIQ==变成?BASIC_AUTH=dXNlcjpw

我需要发送一些基本的身份验证凭据。用户:以查询参数es的形式传递给nginx。http://example.com?BASIC_AUTH=dXNlcjpwYXNz 并且能够以更常见的授权方式(基本的dXNlcjpwYXNz头格式)将它们转发到代理后面的目标服务器

我已经能够用正则表达式检索编码的auth字符串的值。问题是,该值通常可能包含一些需要在URL中进行百分比编码的字符。锿。用户:通过!->?BASIC_AUTH=dXNlcjpwYXNzIQ==变成?BASIC_AUTH=dXNlcjpwYXNzIQ%3D%3D

因此,当我将请求转发到目标服务器时,我最终指定了授权:Basic dXNlcjpwYXNzIQ%3D%3D,目标服务器将拒绝该授权,并给出401个未经授权的消息

在设置授权头之前,如何强制nginx解码auth字符串?提前感谢你的帮助

注意:由于某些特定于应用程序的限制,我无法首先在授权标头中发送auth字符串。

Pure nginx解决方案 不幸的是,nginx不提供富字符串操作集。我认为没有一种方法可以通过某个字符串进行全局搜索和替换,如果我们可以将所有%2B替换为+,%2F替换为/和%3D替换为=,则该字符串可能是一种解决方案。然而,在某些情况下,nginx会对某个字符串执行url解码——当该字符串成为将转发到上游代理服务器的URI的一部分时

因此,我们可以向URI添加一个基本的_AUTH request参数值,并向自己发出代理请求:

# Main server block
server {
    listen 80 default_server;
    ...

    location / {
        if ($arg_basic_auth) {
            # "basic_auth" request argument is present,
            # append "/decode_basic_auth/<BASE64_token>" to the URI
            # and go to the next location block
            rewrite ^(.*)$ /decode_basic_auth/$arg_basic_auth$1 last;
        }
        # No "basic_auth" request argument present,
        # can do a proxy call from here without setting authorization headers
        ...
    }

    location /decode_basic_auth/ {
        # This will be an internal location only
        internal;
        # Remove "basic_auth" request argument from the list of arguments
        if ($args ~* (.*)(^|&)basic_auth=[^&]*(\2|$)&?(.*)) {
            set $args $1$3$4;
        }
        # Some hostname for processing proxy subrequests
        proxy_set_header Host internal.basic.auth.localhost;
        # Do a subrequest to ourselfs, preserving other request arguments
        proxy_pass http://127.0.0.1$uri$is_args$args;
    }
}

# Additional server block for proxy subrequests processing
server {
    listen 80;
    server_name internal.basic.auth.localhost;

    # Got URI in form "/decode_basic_auth/<BASE64_token>/<Original_URI>"
    location ~ ^/decode_basic_auth/([^/]+)(/.*)$ {
        proxy_set_header Authorization "Basic $1";
        # Setup other HTTP headers here
        ...
        proxy_pass http://<upstream_server>$2$is_args$args;
    }

    # Do not serve other requests
    location / {
        return 444;
    }
}
也许这不是一个非常优雅的解决方案,但它已经过测试并且可以工作

OpenResty/ngx_http_lua_模块 这可以通过以下功能轻松解决:

server {
    listen 80 default_server;
    ...

    location / {
        set $auth $arg_basic_auth;
        if ($args ~* (.*)(^|&)basic_auth=[^&]*(\2|$)&?(.*)) {
            set $args $1$3$4;
        }
        rewrite_by_lua_block {
            ngx.var.auth = ngx.unescape_uri(ngx.var.auth)
        }
        proxy_set_header Authorization "Basic $auth";
        # Setup other HTTP headers here
        ...
        proxy_pass http://<upstream_server>;
    }
}
纯nginx溶液 不幸的是,nginx不提供富字符串操作集。我认为没有一种方法可以通过某个字符串进行全局搜索和替换,如果我们可以将所有%2B替换为+,%2F替换为/和%3D替换为=,则该字符串可能是一种解决方案。然而,在某些情况下,nginx会对某个字符串执行url解码——当该字符串成为将转发到上游代理服务器的URI的一部分时

因此,我们可以向URI添加一个基本的_AUTH request参数值,并向自己发出代理请求:

# Main server block
server {
    listen 80 default_server;
    ...

    location / {
        if ($arg_basic_auth) {
            # "basic_auth" request argument is present,
            # append "/decode_basic_auth/<BASE64_token>" to the URI
            # and go to the next location block
            rewrite ^(.*)$ /decode_basic_auth/$arg_basic_auth$1 last;
        }
        # No "basic_auth" request argument present,
        # can do a proxy call from here without setting authorization headers
        ...
    }

    location /decode_basic_auth/ {
        # This will be an internal location only
        internal;
        # Remove "basic_auth" request argument from the list of arguments
        if ($args ~* (.*)(^|&)basic_auth=[^&]*(\2|$)&?(.*)) {
            set $args $1$3$4;
        }
        # Some hostname for processing proxy subrequests
        proxy_set_header Host internal.basic.auth.localhost;
        # Do a subrequest to ourselfs, preserving other request arguments
        proxy_pass http://127.0.0.1$uri$is_args$args;
    }
}

# Additional server block for proxy subrequests processing
server {
    listen 80;
    server_name internal.basic.auth.localhost;

    # Got URI in form "/decode_basic_auth/<BASE64_token>/<Original_URI>"
    location ~ ^/decode_basic_auth/([^/]+)(/.*)$ {
        proxy_set_header Authorization "Basic $1";
        # Setup other HTTP headers here
        ...
        proxy_pass http://<upstream_server>$2$is_args$args;
    }

    # Do not serve other requests
    location / {
        return 444;
    }
}
也许这不是一个非常优雅的解决方案,但它已经过测试并且可以工作

OpenResty/ngx_http_lua_模块 这可以通过以下功能轻松解决:

server {
    listen 80 default_server;
    ...

    location / {
        set $auth $arg_basic_auth;
        if ($args ~* (.*)(^|&)basic_auth=[^&]*(\2|$)&?(.*)) {
            set $args $1$3$4;
        }
        rewrite_by_lua_block {
            ngx.var.auth = ngx.unescape_uri(ngx.var.auth)
        }
        proxy_set_header Authorization "Basic $auth";
        # Setup other HTTP headers here
        ...
        proxy_pass http://<upstream_server>;
    }
}