Wie kann ich den Authentifizierungsdialog des Browsers unterdrücken?

84

Meine Webanwendung verfügt über eine Anmeldeseite, auf der Authentifizierungsdaten über einen AJAX-Aufruf übermittelt werden. Wenn der Benutzer den richtigen Benutzernamen und das richtige Passwort eingibt, ist alles in Ordnung. Wenn nicht, geschieht Folgendes:

  1. Der Webserver stellt fest, dass die Anmeldeinformationen im Header nicht erfolgreich authentifiziert werden, obwohl die Anforderung einen wohlgeformten Autorisierungsheader enthielt.
  2. Der Webserver gibt einen 401-Statuscode zurück und enthält einen oder mehrere WWW-Authenticate-Header, in denen die unterstützten Authentifizierungstypen aufgeführt sind.
  3. Der Browser erkennt, dass die Antwort auf meinen Aufruf des XMLHttpRequest-Objekts 401 ist und die Antwort WWW-Authenticate-Header enthält. Daraufhin wird ein Authentifizierungsdialog angezeigt, in dem Sie erneut nach dem Benutzernamen und dem Kennwort gefragt werden.

Dies ist bis Schritt 3 in Ordnung. Ich möchte nicht, dass der Dialog angezeigt wird. Ich möchte die 401-Antwort in meiner AJAX-Rückruffunktion verarbeiten. (Zum Beispiel durch Anzeigen einer Fehlermeldung auf der Anmeldeseite.) Ich möchte, dass der Benutzer seinen Benutzernamen und sein Kennwort erneut eingibt, aber ich möchte, dass er mein freundliches, beruhigendes Anmeldeformular sieht, nicht die hässliche Standardeinstellung des Browsers Authentifizierungsdialog.

Im Übrigen habe ich keine Kontrolle über den Server, daher ist es keine Option, einen benutzerdefinierten Statuscode (dh etwas anderes als einen 401) zurückzugeben.

Kann ich den Authentifizierungsdialog auf irgendeine Weise unterdrücken? Kann ich insbesondere das Dialogfeld "Authentifizierung erforderlich" in Firefox 2 oder höher unterdrücken? Gibt es eine Möglichkeit, das Dialogfeld Mit [Host] verbinden in IE 6 und höher zu unterdrücken ?


Bearbeiten
Zusätzliche Informationen des Autors (18. September):
Ich sollte hinzufügen, dass das eigentliche Problem beim Auftauchen des Authentifizierungsdialogs des Browsers darin besteht, dass dem Benutzer nicht genügend Informationen zur Verfügung gestellt werden.

Der Benutzer hat gerade einen Benutzernamen und ein Passwort über das Formular auf der Anmeldeseite eingegeben. Er glaubt, beide korrekt eingegeben zu haben, und hat auf die Schaltfläche "Senden" geklickt oder die Eingabetaste gedrückt. Er erwartet, dass er auf die nächste Seite weitergeleitet wird oder dass ihm mitgeteilt wird, dass er seine Informationen falsch eingegeben hat und es erneut versuchen sollte. Stattdessen wird ihm jedoch ein unerwartetes Dialogfeld angezeigt.

Der Dialog macht keine Anerkennung der Tatsache , dass er gerade tat , einen Benutzernamen und ein Passwort eingeben. Es ist nicht klar, dass es ein Problem gab und dass er es erneut versuchen sollte. Stattdessen werden dem Benutzer im Dialogfeld kryptische Informationen wie "Die Site sagt: ' [Realm] '" angezeigt . Wobei [Realm] ein kurzer Realm-Name ist, den nur ein Programmierer lieben kann.

Webbrowser-Designer nehmen zur Kenntnis: Niemand würde fragen, wie der Authentifizierungsdialog unterdrückt werden kann, wenn der Dialog selbst einfach benutzerfreundlicher wäre. Der gesamte Grund, warum ich ein Anmeldeformular mache, ist, dass unser Produktmanagement-Team die Authentifizierungsdialoge der Browser zu Recht für schrecklich hält.

dgvid
quelle
1
Die Antwort ist, dass es keine gute Antwort gibt. Die von Marijn vorgeschlagenen Hacks sind so nah wie möglich. Wenn dies möglich ist, reicht es natürlich auch aus, eine benutzerdefinierte Authentifizierung zu verwenden, die vom Server und Ihrem JavaScript, jedoch nicht vom Browser verstanden wird.
dgvid
Ich war am selben Problem und habe diesen Link in einem Kommentar hier auf stackoverflow (nicht in meinem Blog) gefunden : oudvchar.blogspot.ca/2010/11/… Ich hoffe, es wird Ihnen helfen.
Gies0r

Antworten:

17

Ich denke nicht, dass dies möglich ist. Wenn Sie die HTTP-Client-Implementierung des Browsers verwenden, wird dieser Dialog immer angezeigt. Zwei Hacks kommen in den Sinn:

  1. Vielleicht geht Flash anders damit um (ich habe es noch nicht versucht), daher kann es hilfreich sein, wenn ein Flash-Film die Anfrage stellt.

  2. Sie können einen 'Proxy' für den Dienst einrichten, auf den Sie auf Ihrem eigenen Server zugreifen, und die Authentifizierungsheader ein wenig ändern lassen, damit der Browser sie nicht erkennt.

Marijn
quelle
"Nicht möglich" scheint die richtige Antwort zu sein, obwohl ich vermute, dass der "Proxy" -Hack den Trick machen würde.
dgvid
@Stobor Die akzeptierte Antwort für das von Ihnen veröffentlichte Duplikat verweist tatsächlich auf diese Frage als Antwort!
8bitjunkie
3
@ 7SpecialGems Guter Fang. Ich habe nicht vorgeschlagen, dass es sich um einen Betrüger handelt. Ich habe einen Link zu der spezifischen Antwort (der WWW-Authentifizierung) erstellt, die 4 Jahre nach der akzeptierten Antwort veröffentlicht wurde. Obwohl ich mich im Nachhinein nicht erinnern kann, warum ich das angeschaut habe oder wie ich es getestet habe.
Stobor
1
Ich versuche, einen nicht autorisierten 401-Fehler mit diesem Code abzufangen: $ .ajaxSetup ({statusCode: {401: function () {RedirectToLogin ();}}}); Der IE zeigt jedoch immer den Authentifizierungsdialog des Browsers an. Wie kann ich diesen Dialog in ASP.Net MVC 2 unterdrücken?
PaulP
@PaulP, wie bereits erwähnt, benötigen Sie einen Proxy, der die Antworten des 401-Statuscodes aus dem WWW-Authenticate-Header entfernt, oder eine Art benutzerdefinierte Serverimplementierung.
Motes
49

Ich bin hier auf dasselbe Problem gestoßen, und der Backend-Techniker in meinem Unternehmen hat ein Verhalten implementiert, das anscheinend als bewährte Methode angesehen wird: Wenn ein Aufruf einer URL einen 401 zurückgibt und der Client den Header festgelegt hat, löscht X-Requested-With: XMLHttpRequestder Server den www-authenticateHeader in seinem Antwort.

Der Nebeneffekt ist, dass das Standard-Authentifizierungs-Popup nicht angezeigt wird.

Stellen Sie sicher, dass für Ihren API-Aufruf der X-Requested-WithHeader festgelegt ist XMLHttpRequest. Wenn ja, bleibt nichts anderes übrig, als das Serververhalten gemäß dieser bewährten Methode zu ändern ...

Antoine Banctel-Chevrel
quelle
2
Wenn das Backend auf Java / Spring basiert, DelegatingAuthenticationEntryPointbehandelt das dieses Verhalten für Sie.
Derek Slife
Danke dafür. Viele Bibliotheken haben dieses Verhalten übernommen, einschließlich Devise
josephnvu
1
Irgendeine Idee, wie man das in Nginx macht? "Wenn ein Aufruf einer URL eine 401 zurückgibt und der Client den Header X-Requested-With: XMLHttpRequest festgelegt hat, löscht der Server den Header" www-authenticate "in seiner Antwort."
Markmnl
18

Der Browser öffnet eine Anmeldeaufforderung, wenn beide der folgenden Bedingungen erfüllt sind:

  1. Der HTTP-Status ist 4xx
  2. WWW-Authenticate Header ist in der Antwort vorhanden

Wenn Sie die HTTP-Antwort steuern können, können Sie den WWW-AuthenticateHeader aus der Antwort entfernen , und der Browser öffnet den Anmeldedialog nicht.

Wenn Sie die Antwort nicht steuern können, können Sie einen Proxy einrichten, um den WWW-AuthenticateHeader aus der Antwort herauszufiltern .

Soweit ich weiß (zögern Sie nicht, mich zu korrigieren, wenn ich falsch liege), gibt es keine Möglichkeit, die Anmeldeaufforderung zu verhindern, sobald der Browser den WWW-AuthenticateHeader erhält .

Rustyx
quelle
Gute Information. Informationen zu gültigen WWW-AuthenticateHeader-Werten finden Sie unter stackoverflow.com/a/1748451/225217
Brice Roncace,
6

Mir ist klar, dass diese Frage und ihre Antworten sehr alt sind. Aber ich bin hier gelandet. Vielleicht werden es auch andere tun.

Wenn Sie Zugriff auf den Code für den Webdienst haben, der den 401 zurückgibt. Ändern Sie in dieser Situation einfach den Dienst, um einen 403 (Verboten) anstelle von 401 zurückzugeben. Der Browser fordert Sie nicht zur Eingabe von Anmeldeinformationen als Antwort auf einen 403 auf. 403 ist der korrekter Code für einen authentifizierten Benutzer, der für eine bestimmte Ressource nicht autorisiert ist. Welches scheint die Situation des OP zu sein.

Aus dem IETF-Dokument zu 403:

Ein Server, der gültige Anmeldeinformationen erhält, die für den Zugriff nicht ausreichen, sollte mit dem Statuscode 403 (Verboten) antworten

Jim Reineri
quelle
4

In Mozilla können Sie dies mit dem folgenden Skript erreichen, wenn Sie das XMLHttpRequest-Objekt erstellen:

xmlHttp=new XMLHttpRequest();
xmlHttp.mozBackgroundRequest = true;
xmlHttp.open("GET",URL,true,USERNAME,PASSWORD);
xmlHttp.send(null);

Die 2. Zeile verhindert das Dialogfeld ....

HNygard
quelle
1
Dies scheint unter Firefox 2 nichts zu bewirken. Es führt zu einem DOM-Sicherheitsfehler, NS_ERROR_DOM_SECURITY_ERR-Code 1000, unter Firefox 3.
dgvid
2

Welche Servertechnologie verwenden Sie und gibt es ein bestimmtes Produkt, das Sie zur Authentifizierung verwenden?

Da der Browser nur seine Arbeit erledigt, müssen Sie meines Erachtens Änderungen auf der Serverseite vornehmen, um keinen 401-Statuscode zurückzugeben. Dies kann mithilfe von benutzerdefinierten Authentifizierungsformularen erfolgen, die das Formular einfach erneut zurückgeben, wenn die Authentifizierung fehlschlägt.

jan.vdbergh
quelle
2

Wenn Sie in Mozilla Land den Parameter mozBackgroundRequest von XMLHttpRequest ( docs ) auf true setzen, werden diese Dialoge unterdrückt und die Anforderungen schlagen einfach fehl. Ich weiß jedoch nicht, wie gut die browserübergreifende Unterstützung ist (einschließlich der Frage, ob die Qualität der Fehlerinformationen zu diesen fehlgeschlagenen Anforderungen für alle Browser sehr gut ist).

Rakslice
quelle
Das Moz-Präfix impliziert keine browserübergreifende Unterstützung (es sei denn, Sie finden ähnliche Parameter, die in jedem der anderen Browser funktionieren).
Brilliand
2

jan.vdbergh hat die Wahrheit, wenn Sie den 401 auf der Serverseite gegen einen anderen Statuscode austauschen können, wird der Browser das Popup nicht abfangen und malen. Eine andere Lösung könnte darin bestehen, den WWW-Authenticate-Header gegen einen anderen benutzerdefinierten Header auszutauschen. Ich glaube nicht, warum die verschiedenen Browser es nicht unterstützen können. In einigen Versionen von Firefox können wir die xhr-Anfrage mit mozBackgroundRequest ausführen, aber in den anderen Browsern? Hier gibt es einen interessanten Link zu diesem Problem in Chromium.

Kalamarico
quelle
1

Ich habe das gleiche Problem mit MVC 5 und VPN. Wenn wir uns außerhalb der DMZ befinden und das VPN verwenden, müssen wir diese Browsermeldung beantworten. Mit .net kümmere ich mich einfach um das Routing des Fehlers mit

<customErrors defaultRedirect="~/Error"  >
  <error statusCode="401" redirect="~/Index"/>
</customErrors>

Bisher hat es funktioniert, weil die Index-Aktion unter dem Home-Controller den Benutzer validiert. Wenn die Anmeldung nicht erfolgreich ist, verfügt die Ansicht in dieser Aktion über Anmeldesteuerelemente, mit denen ich den Benutzer mithilfe einer an Directory Services übergebenen LDAP-Abfrage anmelde:

      DirectoryEntry entry = new DirectoryEntry("LDAP://OurDomain");
      DirectorySearcher Dsearch = new DirectorySearcher(entry);
      Dsearch.Filter = "(SAMAccountName=" + UserID + ")";
      Dsearch.PropertiesToLoad.Add("cn");

Obwohl dies bisher gut funktioniert hat und ich Sie wissen lassen muss, dass ich es noch teste und der obige Code keinen Grund zum Ausführen hatte, kann er entfernt werden. Das Testen umfasst derzeit den Versuch, einen Fall zu ermitteln, in dem der zweite Satz vorliegt Code ist nicht mehr von Nutzen. Auch dies ist noch in Arbeit, aber da es hilfreich sein oder Ihr Gehirn für einige Ideen anregen könnte, habe ich beschlossen, es jetzt hinzuzufügen ... Ich werde es mit den endgültigen Ergebnissen aktualisieren, sobald alle Tests abgeschlossen sind.

Clarence
quelle
1

Ich verwende Node, Express & Passport und hatte mit dem gleichen Problem zu kämpfen. Ich habe es zum Laufen gebracht, indem ich den www-authenticateHeader explizit auf eine leere Zeichenfolge gesetzt habe. In meinem Fall sah es so aus:

(err, req, res, next) => {
  if (err) {
    res._headers['www-authenticate'] = ''
    return res.json(err)
  }
}

Ich hoffe das hilft jemandem!

John Knotts
quelle
0

Für diejenigen , unsing C # ist hier , ActionAttributedass die Renditen 400statt 401, und ‚schluckt‘ Grund Auth Dialog.

public class NoBasicAuthDialogAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        base.HandleUnauthorizedRequest(filterContext);
        filterContext.Result = new HttpStatusCodeResult(400);
    }
}

Verwenden Sie wie folgt:

[NoBasicAuthDialogAuthorize(Roles = "A-Team")]
public ActionResult CarType()
{
 // your code goes here
}

Hoffe das spart dir etwas Zeit.

Matas Vaitkevicius
quelle