Ich habe einen Upstream-Server, der das Login unserer Website verwaltet. Bei einer erfolgreichen Anmeldung möchte ich den Benutzer zum sicheren Teil der Site umleiten. Bei einem fehlgeschlagenen Login möchte ich den Benutzer zum Login-Formular umleiten.
Der Upstream-Server gibt 200 OK
bei einer erfolgreichen Anmeldung eine und 401 Unauthorized
bei einer fehlgeschlagenen Anmeldung eine zurück.
Dies ist der relevante Teil meiner Konfiguration:
{
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
}
}
Dieses Setup funktioniert, wenn die Anmeldung erfolgreich war. Der Client wird mit einem 302 umgeleitet. Dies funktioniert nicht , wenn die Anmeldung fehlschlägt. Der Upstream-Server gibt 401 zurück und ich habe erwartet, dass der error_page
dann einschaltet. Aber ich bekomme immer noch den 302. Wenn ich die return 302 /secure/
Zeile entferne, funktioniert die Umleitung zur Anmeldeseite. Es scheint also, dass ich eins haben kann, aber nicht beide.
Bonus-Frage; Ich bezweifle, dass die Art und Weise, wie ich error_page
mit dem genannten Ort umgehe, The Way ist. Habe ich recht damit?
edit : Es stellt sich heraus, dass ein return
im location
Block enthaltenes Nginx das überhaupt nicht verwendet proxy_pass
. Es ist also sinnvoll, dass die Fehlerseite nicht getroffen wird. Das Problem, wie dies zu tun ist, bleibt jedoch bestehen.
200 OK
scheint beim Erfolg der Anmeldung völlig vernünftig zu sein (dies ergibt einen Cookie) und401 Unauthorized
scheint auch in Ordnung zu sein.Antworten:
Die genaue Lösung der Frage besteht darin, die Lua-Funktionen von Nginx zu nutzen.
Unter Ubuntu 16.04 können Sie eine Version von Nginx installieren, die Lua unterstützt mit:
Auf anderen Systemen kann dies anders sein. Sie können sich auch für die Installation von OpenResty entscheiden.
Mit Lua haben Sie vollen Zugriff auf die Upstream-Antwort. Beachten Sie , dass Sie scheinbar über die
$upstream_status
Variable Zugriff auf den Upstream-Status haben . Und auf eine Art und Weise, die Sie tun, aber aufgrund der Art und Weise, wie 'if'-Anweisungen in Nginx ausgewertet werden, können Sie sie nicht$upstream_status
in der' if'-Anweisung verwenden.Mit Lua sieht Ihre Konfiguration dann folgendermaßen aus:
Ziemlich einfach. Die einzigen zwei Macken sind das Lesen des Anforderungshauptteils, um die POST-Parameter weiterzugeben, und das Setzen des Cookies in der endgültigen Antwort an den Client.
Was ich tatsächlich getan habe, nachdem ich viel von der Community gestoßen wurde, ist, dass ich die Upstream-Stream-Antworten auf der Client-Seite bearbeitet habe. Dadurch blieb der Upstream-Server unverändert und meine Nginx-Konfiguration einfach:
Der Client, der die Anforderung initialisiert, verarbeitet die Upstream-Antwort:
Die obige Lösung erreicht mein Ziel einer klaren Trennung der Bedenken. Der Authentifizierungsserver kennt die Anwendungsfälle nicht, die die Anrufer unterstützen möchten.
quelle
Obwohl ich @ michael-hampton vollkommen zustimme, dh, dass dieses Problem nicht von nginx behandelt werden sollte, haben Sie versucht,
error_page
in den Standortblock zu wechseln:quelle
Ich bin mir nicht ganz sicher, ob das Folgende funktioniert, und ich teile die Ansicht von Michael, aber Sie könnten versuchen, das HTTP-Authentifizierungsanforderungsmodul zu verwenden , vielleicht etwas in dieser Richtung:
Sie würden dieses Konfigurations-Snippet nicht auf dem Server verwenden, der die eigentliche Authentifizierung durchführt, sondern auf dem Server, auf dem sich der geschützte Inhalt befindet. Ich konnte das momentan nicht testen, aber vielleicht hilft dir das immer noch.
Zu Ihrer Bonusfrage: Ja, AFAIK, so sollte das gehandhabt werden.
quelle
error_page
Ich werde das nicht tun lassen. Das Hinzufügenreturn
deslocation
Blocks verhindert, dass die andereerror_page
Direktive funktioniert.200 OK
? Warum ist es nicht möglich, den Benutzer auf den Inhalt zugreifen zu lassen, wenn er einen erhält200 OK
, und nur umzuleiten, wenn er einen erhält401
?/secure
,auth_request
und das funktioniert absolut großartig. Aber ich suche nach einer Lösung, wenn sich ein Benutzer anmeldet . Der Benutzer sendet ein Formular an/login
. Entweder hat er eine korrekte Kombination aus Benutzername und Passwort angegeben oder nicht. Wenn er zu umgeleitet hat/secure
(was eine ergibtauth_request
), wenn er nicht zum Anmeldeformular zurückgeleitet hat.login.example.com
dem Benutzer das Auth-Cookie zur Verfügung gestellt und haben wahrscheinlich alle möglichen Verhaltensweisen in dieser Domain (Umgang mit Registrierung und Anmeldefluss). Ich möchte das in Nginx kodieren, damit ich dafür keine separate App schreiben muss. Aber es scheint, ich muss.Das Verhalten, das Sie sehen, wird erwartet, da
return
es alles ersetzt, was Ihre Umschreibungen generiert haben.Ich stimme Michael Hampton zwar voll und ganz zu, aber wenn Sie wirklich keine anderen Optionen haben, können Sie Folgendes ausprobieren. Bitte denken Sie daran, dass dies ein schmutziger Hack ist. Sie müssen Ihre Architektur in erster Linie berücksichtigen:
quelle
$upstream_status
scheint völlig ignoriert zu werden. Bei dieser Konfiguration ist die Antwort nur die Upstream-Antwort.add_header X-Debug $upstream_status always;
Ich kann den richtigen Status ausgegeben sehen. Vielleicht sollte der Test in der if-Anweisung anders sein?200
zu302 /secure/
und401
zu übersetzt302 /login.html
?