我有一个有效的设计来验证 Nginx/njs 中的 API 密钥。让我向您展示我的最终解决方案,然后问几个与我在此过程中遇到的问题相关的问题(我很想了解为什么这些其他选项不起作用)。
这是我的 nginx.conf:
js_include validate-api-keys.js;
server {
# We try to always use port 9000 (by convention) for our application entrypoints.
listen 9000;
server_name localhost;
location = /health {
# Always pass the health check to the reverse-proxied server
proxy_pass http://localhost:8080;
}
location / {
# Validate that the api-key header matches the API_KEY_CURRENT or API_KEY_PREVIOUS env var
js_content validate_api_key;
# Q1: the following commented config didn't work (why was it ALWAYS doing the proxy_pass?):
# My goal was: if the above js code didn't already return a 401 response, pass the request to the reversed proxied app
# proxy_pass http://localhost:8080;
}
# This location is internal (only nginx itself can call this location)
location @app-backend {
proxy_pass http://localhost:8080;
}
# Removed this, the subrequest in the JS didn't work:
# location /internalProxyPassToBackend {
# internal;
# proxy_pass http://localhost:8080;
# }
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
这是我的 validate-api-keys.js(请忽略“UNCOMMENT TO DEBUG”注释,这只是一个调试技巧:我监视返回的响应标头以查看代码的去向、值是什么等):
function validate_api_key(r) {
// UNCOMMENT TO DEBUG: r.headersOut['validate_api_key-start'] = 'Log at START of validate_api_key'
var requestApiKey = r.headersIn["api-key"];
// UNCOMMENT TO DEBUG: r.headersOut['validate_api_key-input-key'] = 'validate_api_key received tpg-api-key header=' + requestApiKey
// Validating API KEY
if (requestApiKey !== "<API_KEY_CURRENT>" && requestApiKey !== "<API_KEY_PREVIOUS>") {
// Return 401 Unauthorized (Access Denied) if key is invalid (doesn't match CURRENT and PREVIOUS key)
// UNCOMMENT TO DEBUG: r.headersOut['validate_api_key-401'] = 'validate_api_key returning 401'
r.return(401, "Access Denied");
} else {
// Send the request to the backend (proxy_pass)
// UNCOMMENT TO DEBUG: r.headersOut['validate_api_key-200'] = 'validate_api_key returning 200'
r.internalRedirect('@app-backend');
// This didn't work (didn't pass the Method.POST):
// r.subrequest('/internalProxyPassToBackend', r.variables)
// .then(reply => r.return(reply.status, reply.responseBody));
// This didn't work (didn't pass the Method.POST):
//r.subrequest('/internalProxyPassToBackend', r.variables,
// function(reply) {
// r.return(reply.status, reply.responseBody);
// return;
// }
// );
}
// UNCOMMENT TO DEBUG: r.headersOut['validate_api_key-end'] = 'Log at END of validate_api_key'
}
Q1:在我的 nginx.conf 中,当我的 js_content 和 proxy_pass 在同一个位置上下文中时,proxy_pass 也会触发,无论我的 javascript(在 js_content 中)是否尝试返回 401。它总是会执行 proxy_pass!这是为什么?我觉得这与“IF在位置块中是邪恶的”具有相同的想法/根本原因?
Q2:如您所见,在我的 JavaScript 中,我终于求助于 r.internalRedirect (效果很好!)但我首先撞到了一堆墙上:我注释掉的代码有什么问题?为什么“r.subrequest”不通过方法(在我的情况下是 POST)?我的后端总是抱怨它不支持“GET”,因为很明显,我的代码没有传递 Method=POST。有谁知道如何使注释掉的代码工作(将初始请求、方法等的所有参数传递给后端)?
感谢您帮助我找出我最初的路径出了什么问题!