Nginx-解码URL查询参数并将其作为请求标头转发 [英] Nginx - Decode URL query parameter and forward it as request header

查看:455
本文介绍了Nginx-解码URL查询参数并将其作为请求标头转发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要以查询参数(es. http://example.com?BASIC_AUTH=dXNlcjpwYXNz)的形式向nginx发送一些基本的身份验证凭据(es. user:pass )),并能够以更常见的 Authorization:Basic dXNlcjpwYXNz 标头形式将它们转发到代理后面的目标服务器.

I need to send some basic auth credentials (es. user:pass) to nginx in the form of query parameter (es. http://example.com?BASIC_AUTH=dXNlcjpwYXNz) and being able to forward them in the more usual Authorization: Basic dXNlcjpwYXNz header form to a target server behind the proxy.

我已经能够使用正则表达式检索编码的身份验证字符串的值.问题在于,该值通常可能包含一些需要在URL中进行百分比编码的字符.Es. user:pass!-> ?BASIC_AUTH = dXNlcjpwYXNzIQ == 变为?BASIC_AUTH = dXNlcjpwYXNzIQ%3D%3D

I'm already able to retrieve the value of the encoded auth string with a regular expression. The problem is that very often that value may contain some character that need to be percent-encoded in the URL. Es. user:pass! -> ?BASIC_AUTH=dXNlcjpwYXNzIQ== becomes ?BASIC_AUTH=dXNlcjpwYXNzIQ%3D%3D

因此,当我将请求转发到目标服务器时,最终要指定目标服务器将拒绝的 Authorization:Basic dXNlcjpwYXNzIQ%3D%3D ,给出401 Unauthorized.

Therefore, when I forward the request to the target server, I end up specifing Authorization: Basic dXNlcjpwYXNzIQ%3D%3D which the target server will reject, giving a 401 Unauthorized.

在设置Authorization标头之前,如何强制nginx解码auth字符串?预先感谢您的帮助.

How can I force nginx to decode the auth string before setting the Authorization header? Thanks in advance for your help.

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

Note: I can't send the auth string in the Authorization header in the first place due to some application-specific constraints.

推荐答案

纯" nginx解决方案

不幸的是,nginx没有提供丰富的字符串操作集.我认为没有办法通过某些字符串进行全局搜索和替换(如果我们可以将所有%2B 替换为 + ,<带有/的code>%2F 和带有 = %3D ).但是,在某些情况下,nginx会对某些字符串执行urldecoding-当此字符串成为URI的一部分时,它将被转发到上游代理服务器.

"Pure" nginx solution

Unfortunately nginx does not provide a rich string operations set. I think there isn't a way to do global search-and-replace through some string (which can be a solution if we could replace all %2B with +, %2F with / and %3D with =). However there are circumstances under which nginx performs an urldecoding of some string - when this string becomes a part of an URI which will be forwarded to an upstream proxy server.

因此,我们可以将 BASIC_AUTH 请求参数的值添加到URI并向我们自己发出代理请求:

So we can add a value of a BASIC_AUTH request argument to the URI and make a proxy request to ourself:

# 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;
    }
}

也许这不是一个非常优雅的解决方案,但是它已经过测试并且可以正常工作.

Maybe this is not a very elegant solution, but it is tested and works.

可以使用 openresty ngx.escape_uri 函数:

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-解码URL查询参数并将其作为请求标头转发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆