Nginx-解码URL查询参数并将其作为请求标头转发 [英] Nginx - Decode URL query parameter and forward it as request header
问题描述
我需要以查询参数(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屋!