Проверка ключа API Nginx/njs: internalRedirect vs subrequest, js_content + validate

У меня есть рабочий дизайн для проверки ключей API в Nginx / njs. Позвольте мне показать вам свое окончательное решение, а затем задать пару вопросов, связанных с проблемами, с которыми я столкнулся на этом пути (мне бы хотелось узнать, почему эти другие варианты не работают).

Это мой 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'
}

В1: в моем nginx.conf, когда у меня были оба js_content и proxy_pass в одном контексте местоположения, proxy_pass также запускался, независимо от того, пытался ли мой javascript (в js_content) вернуть 401. Он всегда будет выполнять proxy_pass! Это почему? Я чувствую, что это имеет ту же идею / основную причину, что и «ЕСЛИ - зло в блоках локации»?

Q2: в моем JavaScript, как вы можете видеть, я наконец прибег к r.internalRedirect (отлично работает!) НО сначала я ударился носом о кучу стен: что не так с моим закомментированным кодом? Почему «r.subrequest» не передает метод (в моем случае POST)? Мой бэкэнд всегда жаловался, что он не поддерживает «GET», потому что, очевидно, мой код не передавал Method=POST. Кто-нибудь знает, как заставить этот закомментированный код работать (передать ВСЕ аргументы начального запроса, метода и т. Д. На бэкэнд)?

Спасибо, что помогли мне понять, что было не так с моим первоначальным путем!

2 ответа

довольно старый, но тоже был там совсем недавно.

В вашем скрипте передайте исходный метод и тело запроса в подзапрос, как показано ниже.

      r.subrequest('/internalProxyPassToBackend', { method: r.method, body: r.requestBody })

и вуаля.

лучший

в конфигурации nginx нужно указать метод прокси

       location /internalProxyPassToBackend {
         internal;            
         proxy_method      POST;             
         proxy_pass http://localhost:8080;
 }
Другие вопросы по тегам