Differenti Nginx reindirizzano sulla base della risposta proxy a monte

Ho un server a monte che gestisce l'accesso del nostro sito web. In un login di successo vorrei redirect l'utente alla parte protetta del sito. Su un errore di login vorrei redirect l'utente al module di login.

Il server a monte restituisce un 200 OK su un login di successo e un 401 Unauthorized su un login non riuscito.

  • Come build nginx 1.4.0 e ngx_pagespeed in Ubuntu / Debian?
  • Il dominio viene reindirizzato al sito sbagliato in nginx, siti multipli nei file di configuration
  • Scarsa performance del bilanciatore del carico su rackspace e centos
  • Come modificare la directory di caricamento temporaneo nginx / passeggero?
  • Reindirizzare tutto, ma ben noto in NGINX (Let's Encrypt)
  • Impostazione del proxy di installazione di PostgreSQL Stack Builder su Windows
  • Questa è la parte rilevante della mia configuration:

     { error_page 401 = @error401 location @error401 { return 302 /login.html # this page holds the login form } location = /login { # this is the POST target of the login form proxy_pass http://localhost:8080; proxy_intercept_errors on; return 302 /secure/; # without this line, failures work. With it failed logins (401 upstream response) still get 302 redirected } } 

    Questa impostazione funziona quando viene eseguito il login. Il client è reindirizzato con un 302. Questo non funziona quando non è in corso il login. Il server a monte restituisce 401 e mi aspettavo che la pagina di error_page avrebbe error_page . Ma ho ancora il 302. Se rimuovo il return 302 /secure/ line, il reindirizzamento alla pagina di login funziona. Quindi sembra che posso avere uno, ma non entrambi.

    Domande bonus; Dubito del modo in cui gestisco il error_page con quella locazione denominata è The Way. Sono corretto farlo così?

    modifica : risulta che un return nel block di location rende Nginx non utilizzare il proxy_pass a tutti. Così ha senso che la pagina di errore non è colpita. Il problema su come farlo tuttavia rimane.

  • Devo includere il certificato CA principale quando crei un certificato incatenato
  • SSL & Ngnix: nessun "ssl_certificate" è definito nell'ascolto del server sulla port SSL mentre SSL handshaking
  • Nginx & PHP-FPM - .php File non trovato - Non riesco a capire perché
  • Django: Nginx con WSGI o Apache con WSGI
  • NGINX Unicorn 504 Gateway Time-out
  • Configurazione di Vox Django
  • 4 Solutions collect form web for “Differenti Nginx reindirizzano sulla base della risposta proxy a monte”

    La soluzione esatta alla domanda è quella di utilizzare le funzionalità di Lua di Nginx.

    Su Ubuntu 16.04 è ansible installare una versione di Nginx che support Lua con:

     $ apt install nginx-extra 

    Su altri sisthemes potrebbe essere diverso. È anche ansible optare per l'installazione di OpenResty.

    Con Lua hai accesso completo alla risposta a monte. Si noti che sembra che tu abbia accesso allo stato a monte tramite la variabile $upstream_status . E in un certo senso lo fai ma a causa del modo in cui le affermazioni 'se' vengono valutate in Nginx non è ansible utilizzare $upstream_status 'if' condizionale.

    Con Lua la tua configuration sarà simile a:

      location = /login { # the POST target of your login form rewrite_by_lua_block { ngx.req.read_body() local res = ngx.location.capture("/login_proxy", {method = ngx.HTTP_POST}) if res.status == 200 then ngx.header.Set_Cookie = res.header["Set-Cookie"] # pass along the cookie set by the backend return ngx.redirect("/shows/") else return ngx.redirect("/login.html") end } } location = /login_proxy { internal; proxy_pass http://localhost:8080/login; } 

    Abbastanza diretto. Le due sollecitazioni sono solo la lettura del corpo di richiesta per passare lungo i parametri POST e l'impostazione del cookie nella risposta finale al client.


    Quello che in realtà ho finito per fare, dopo un gran numero di prodezze dalla comunità, è che ho gestito le risposte a monte del stream sul lato client. Questo ha lasciato invariato il server a monte e la mia configuration Nginx semplice:

     location = /login { proxy_pass http://localhost:8080; } 

    Il client che inizia la richiesta gestisce la risposta a monte:

      <body> <form id='login-form' action="/login" method="post"> <input type="text" name="username"> <input type="text" name="password"> <input type="submit"> </form> <script type='text/javascript'> const form = document.getElementById('login-form'); form.addEventListener('submit', (event) => { const data = new FormData(form); const postRepresentation = new URLSearchParams(); // My upstream auth server can't handle the "multipart/form-data" FormData generates. postRepresentation.set('username', data.get('username')); postRepresentation.set('password', data.get('password')); event.preventDefault(); fetch('/login', { method: 'POST', body: postRepresentation, }) .then((response) => { if (response.status === 200) { console.log('200'); } else if (response.status === 401) { console.log('401'); } else { console.log('we got an unexpected return'); console.log(response); } }); }); </script> </body> 

    La soluzione sopra raggiunge il mio objective di avere una chiara separazione delle preoccupazioni. Il server di authentication è ignaro dei casi di utilizzo che i chiamanti desiderano supportre.

    Mentre sono pienamente d'accordo con @ michael-hampton, cioè che questo problema non deve essere gestito da nginx, hai provato a spostare l'pagina di error_page nel block di posizione:

     { location @error401 { return 302 /login.html # this page holds the login form } location = /login { # this is the POST target of the login form proxy_pass http://localhost:8080; proxy_intercept_errors on; error_page 401 = @error401; return 302 /secure/; # without this line, failures work. With it failed logins (401 upstream response) still get 302 redirected } } 

    Non sono del tutto sicuro se le seguenti funzioni, e condivido la vista di Michael, ma si potrebbe provare a utilizzare il module di richiesta HTTP HTTP , forse qualcosa in questo modo:

     location /private/ { auth_request /auth; ... } location = /auth { proxy_pass ... proxy_pass_request_body off; proxy_set_header Content-Length ""; # This is only needed if your auth server uses this information, # for example if you're hosting different content which is # only accessible to specific groups, not all of them, so your # auth server checks "who" and "what" proxy_set_header X-Original-URI $request_uri; error_page 401 = @error401; } location @error401 { return 302 /login.html } 

    Si utilizza questo frammento di configuration non sul server che esegue l'authentication effettiva, ma sul server che ospita il contenuto protetto. Non ho potuto provare adesso, ma forse questo è ancora di aiuto per te.

    Per quanto riguarda la tua domanda bonus: Sì, AFAIK, questo è il modo in cui questo dovrebbe essere gestito.

    Il comportmento che si vede è previsto, poiché il return sostituirà ciò che è stato generato dalla tua riscrittura.

    Mentre sono completamente d'accordo con Michael Hampton, se sei davvero fuori di altre opzioni potresti provare qualcosa nel seguito. Si prega di tenere presente che questo è un hack sporco, in realtà è necessario considerare la vostra architettura in primo luogo:

     upstream backend { server http://localhost:8080; } server { location / { proxy_pass http://backend; if ($upstream_status = 401) { return 302 /login.html; } if ($upstream_status = 200) { return 302 /secure/; } } } 
    Suggerimenti per Linux e Windows Server, quali Ubuntu, Centos, Apache, Nginx, Debian e argomenti di rete.