Jak mogę pominąć okno dialogowe uwierzytelniania przeglądarki?

85

Moja aplikacja internetowa ma stronę logowania, która przesyła dane uwierzytelniające za pośrednictwem wywołania AJAX. Jeśli użytkownik wprowadzi poprawną nazwę użytkownika i hasło, wszystko jest w porządku, ale jeśli nie, dzieje się tak:

  1. Serwer WWW stwierdza, że ​​chociaż żądanie zawierało poprawnie sformułowany nagłówek Authorization, poświadczenia w nagłówku nie są pomyślnie uwierzytelniane.
  2. Serwer sieciowy zwraca kod stanu 401 i zawiera jeden lub więcej nagłówków WWW-Authenticate wymieniających obsługiwane typy uwierzytelniania.
  3. Przeglądarka wykrywa, że ​​odpowiedź na moje wywołanie obiektu XMLHttpRequest to 401, a odpowiedź zawiera nagłówki WWW-Authenticate. Następnie pojawia się okno dialogowe uwierzytelniania z pytaniem o nazwę użytkownika i hasło.

Do kroku 3 wszystko jest w porządku. Nie chcę, aby pojawiło się okno dialogowe, chcę obsłużyć odpowiedź 401 w mojej funkcji wywołania zwrotnego AJAX. (Na przykład wyświetlając komunikat o błędzie na stronie logowania). Oczywiście chcę, aby użytkownik ponownie wprowadził swoją nazwę użytkownika i hasło, ale chcę, aby zobaczył mój przyjazny, uspokajający formularz logowania, a nie brzydki, domyślny okno dialogowe uwierzytelniania.

Nawiasem mówiąc, nie mam kontroli nad serwerem, więc zwrócenie przez niego niestandardowego kodu stanu (tj. Czegoś innego niż 401) nie jest opcją.

Czy jest jakiś sposób, aby ukryć okno dialogowe uwierzytelniania? W szczególności, czy mogę pominąć okno dialogowe Wymagane uwierzytelnienie w przeglądarce Firefox 2 lub nowszej? Czy istnieje sposób na pominięcie okna dialogowego Połącz z [hostem] w przeglądarce IE 6 i nowszych?


Edytuj
Dodatkowe informacje od autora (18 września):
Powinienem dodać, że prawdziwym problemem z wyskakującym oknem dialogowym uwierzytelniania przeglądarki jest to, że podaje ono użytkownikowi niewystarczające informacje.

Użytkownik właśnie wprowadził nazwę użytkownika i hasło za pośrednictwem formularza na stronie logowania, uważa, że ​​wpisał je poprawnie i kliknął przycisk przesyłania lub wcisnął Enter. Oczekuje, że zostanie przeniesiony na następną stronę lub może powiedziano mu, że wprowadził nieprawidłowe informacje i powinien spróbować ponownie. Jednak zamiast tego jest wyświetlane nieoczekiwane okno dialogowe.

Okno nie ma potwierdzenia faktu, że właśnie zrobił wprowadzić nazwę użytkownika i hasło. Nie stwierdza jasno, że wystąpił problem i że powinien spróbować ponownie. Zamiast tego okno dialogowe przedstawia użytkownikowi tajemnicze informacje, takie jak „Witryna mówi: ' [dziedzina] '”. Gdzie [dziedzina] to krótka nazwa dziedziny, którą może pokochać tylko programista.

Uwaga projektanci przeglądarek internetowych: nikt nie zapytałby, jak pominąć okno dialogowe uwierzytelniania, gdyby samo okno dialogowe było po prostu bardziej przyjazne dla użytkownika. Cały powód, że robię formularz logowania jest to, że nasz zespół zarządzania produktem słusznie uważa dialogi uwierzytelniania przeglądarek być okropne.

dgvid
źródło
1
Odpowiedź jest taka, że ​​nie ma dobrej odpowiedzi. Hacki sugerowane przez Marijna są tak bliskie, jak to tylko możliwe. Oczywiście użycie niestandardowego uwierzytelnienia zrozumiałego dla serwera i JavaScript, ale nie przez przeglądarkę, również załatwi sprawę, jeśli to możliwe.
dgvid
Byłem w tym samym problemie i znalazłem ten link w komentarzu na stackoverflow (nie na moim blogu): loudvchar.blogspot.ca/2010/11/ ... Mam nadzieję, że to ci pomoże.
gies0r

Odpowiedzi:

17

Nie sądzę, żeby to było możliwe - jeśli używasz implementacji klienta HTTP przeglądarki, zawsze pojawi się to okno dialogowe. Przychodzą mi na myśl dwa hacki:

  1. Może Flash radzi sobie z tym inaczej (jeszcze nie próbowałem), więc posiadanie filmu flashowego sprawi, że żądanie może pomóc.

  2. Możesz skonfigurować „serwer proxy” dla usługi, do której uzyskujesz dostęp na własnym serwerze, i poprosić go o nieco zmodyfikowanie nagłówków uwierzytelniania, aby przeglądarka ich nie rozpoznawała.

Marijn
źródło
„Niemożliwe” wydaje się być poprawną odpowiedzią, chociaż podejrzewam, że włamanie do „proxy” załatwi sprawę.
dgvid
@Stobor Zaakceptowana odpowiedź na opublikowany przez Ciebie duplikat w rzeczywistości zawiera odnośnik do tego pytania!
8bitjunkie,
3
@ 7SpecialGems Dobry chwyt. Nie sugerowałem, że to oszustwo, podałem link do konkretnej odpowiedzi (WWW-Authenticate), która została opublikowana 4 lata po zaakceptowanej odpowiedzi. Chociaż z perspektywy czasu nie pamiętam, dlaczego na to patrzyłem ani jak to przetestowałem.
Stobor
1
Próbuję wyłapać nieautoryzowany błąd 401 tym kodem: $ .ajaxSetup ({statusCode: {401: function () {RedirectToLogin ();}}}); Ale IE zawsze wyświetla okno dialogowe uwierzytelniania przeglądarki. Jak mogę pominąć to okno dialogowe w ASP.Net MVC 2?
PaulP
@PaulP, jak powiedziano, potrzebujesz serwera proxy, który usunie odpowiedzi kodu stanu 401 z nagłówka WWW-Authenticate lub jakiejś niestandardowej implementacji serwera.
Motes
51

Napotkałem ten sam problem i inżynier zaplecza w mojej firmie zaimplementował zachowanie, które najwyraźniej jest uważane za dobrą praktykę: gdy wywołanie adresu URL zwraca 401, jeśli klient ustawił nagłówek X-Requested-With: XMLHttpRequest, serwer upuszcza www-authenticatenagłówek w swoim odpowiedź.

Efektem ubocznym jest to, że domyślne okienko uwierzytelniania nie jest wyświetlane.

Upewnij się, że wywołanie interfejsu API ma X-Requested-Withnagłówek ustawiony na XMLHttpRequest. Jeśli tak, nie pozostaje nic innego, jak zmienić zachowanie serwera zgodnie z tą dobrą praktyką ...

Antoine Banctel-Chevrel
źródło
3
Jeśli backend jest oparty na Javie / Springie, DelegatingAuthenticationEntryPointobsługuje to zachowanie za Ciebie.
Derek Slife
Dziękuję Ci za to. Wiele bibliotek przyjęło to zachowanie, w tym Devise
josephnvu
1
jakiś pomysł, jak to zrobić w nginx? „gdy wywołanie adresu URL zwraca 401, jeśli klient ustawił nagłówek X-Requested-With: XMLHttpRequest, serwer odrzuca w odpowiedzi nagłówek www-authentication”.
markmnl
18

Przeglądarka wyświetla monit logowania, gdy spełnione są oba poniższe warunki:

  1. Stan HTTP to 4xx
  2. WWW-Authenticate nagłówek jest obecny w odpowiedzi

Jeśli możesz kontrolować odpowiedź HTTP, możesz usunąć WWW-Authenticatenagłówek z odpowiedzi, a przeglądarka nie wyświetli okna dialogowego logowania.

Jeśli nie możesz kontrolować odpowiedzi, możesz skonfigurować serwer proxy, aby odfiltrować WWW-Authenticatenagłówek z odpowiedzi.

O ile wiem (jeśli się mylę, nie wahaj się mnie poprawić), nie ma sposobu, aby zapobiec wyświetlaniu monitu o logowanie, gdy przeglądarka otrzyma WWW-Authenticatenagłówek.

rustyx
źródło
Dobra informacja. Odnośnie prawidłowych WWW-Authenticatewartości nagłówka, patrz stackoverflow.com/a/1748451/225217
Brice Roncace
6

Zdaję sobie sprawę, że to pytanie i odpowiedzi na nie są bardzo stare. Ale skończyłem tutaj. Być może inni też.

Jeśli masz dostęp do kodu usługi sieciowej, która zwraca 401. Po prostu zmień usługę, aby zwracała 403 (zabronione) w tej sytuacji zamiast 401. Przeglądarka nie będzie pytać o poświadczenia w odpowiedzi na 403. 403 to poprawny kod dla uwierzytelnionego użytkownika, który nie jest autoryzowany do określonego zasobu. Tak wygląda sytuacja PO.

Z dokumentu IETF na 403:

Serwer, który otrzymuje ważne dane uwierzytelniające, które nie są wystarczające do uzyskania dostępu, powinien odpowiedzieć kodem statusu 403 (zabronione)

Jim Reineri
źródło
4

W Mozilli możesz to osiągnąć za pomocą następującego skryptu podczas tworzenia obiektu XMLHttpRequest:

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

Druga linia zapobiega wyświetlaniu okna dialogowego ....

HNygard
źródło
1
Wydaje się, że nie działa to w przeglądarce Firefox 2. Powoduje to błąd zabezpieczeń DOM, NS_ERROR_DOM_SECURITY_ERR kod 1000, w przeglądarce Firefox 3.
dgvid
2

Z jakiej technologii serwerowej korzystasz i czy jest jakiś konkretny produkt, którego używasz do uwierzytelniania?

Ponieważ przeglądarka wykonuje tylko swoją pracę, uważam, że musisz zmienić rzeczy po stronie serwera, aby nie zwracać kodu stanu 401. Można to zrobić za pomocą niestandardowych formularzy uwierzytelniania, które po prostu zwracają formularz ponownie, gdy uwierzytelnianie się nie powiedzie.

jan.vdbergh
źródło
2

W krainie Mozilli ustawienie parametru mozBackgroundRequest XMLHttpRequest ( docs ) na true powoduje zablokowanie tych okien dialogowych i powoduje, że żądania po prostu kończą się niepowodzeniem. Jednak nie wiem, jak dobra jest obsługa różnych przeglądarek (w tym, czy jakość informacji o błędach w tych nieudanych żądaniach jest bardzo dobra w różnych przeglądarkach).

rakslice
źródło
Przedrostek moz- oznacza brak obsługi różnych przeglądarek (chyba że możesz znaleźć podobne parametry, które działają w każdej z pozostałych przeglądarek).
Brilliand
2

jan.vdbergh ma prawdę, jeśli możesz zmienić 401 po stronie serwera na inny kod statusu, przeglądarka nie złapie i nie zamaluje wyskakującego okienka. Innym rozwiązaniem może być zmiana nagłówka WWW-Authenticate na inny niestandardowy nagłówek. Nie wierzę, dlaczego inna przeglądarka tego nie obsługuje, w kilku wersjach Firefoksa możemy wykonać żądanie xhr za pomocą mozBackgroundRequest, ale w innych przeglądarkach? tutaj jest ciekawy link do tego wydania w Chromium.

Kalamarico
źródło
1

Mam ten sam problem z MVC 5 i VPN, gdzie za każdym razem, gdy jesteśmy poza strefą DMZ, używając VPN, musimy odpowiedzieć na tę wiadomość przeglądarki. Używając .net, po prostu obsługuję routing błędu za pomocą

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

do tej pory zadziałało, ponieważ akcja Indeks pod kontrolerem macierzystym weryfikuje użytkownika. Widok w tej akcji, jeśli logowanie się nie powiedzie, zawiera kontrolki logowania, których używam do logowania użytkownika przy użyciu zapytania LDAP przekazanego do usług katalogowych:

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

Chociaż jak dotąd działało to dobrze i muszę poinformować, że nadal go testuję, a powyższy kod nie miał powodu do uruchomienia, więc podlega usunięciu ... obecnie testowanie obejmuje próbę wykrycia przypadku, w którym drugi zestaw kodu jest już przydatny. Ponownie, jest to w toku, ale ponieważ może to być pomoc lub pobudzić mózg do pewnych pomysłów, postanowiłem to teraz dodać ... Zaktualizuję to o ostateczne wyniki, gdy wszystkie testy zostaną zakończone.

Clarence
źródło
1

Używam Node, Express i Passport i zmagałem się z tym samym problemem. Mam to do pracy, jawnie ustawiając www-authenticatenagłówek na pusty ciąg. W moim przypadku wyglądało to tak:

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

Mam nadzieję, że to komuś pomoże!

John Knotts
źródło
0

Dla tych, którzy nie używają języka C #, oto, ActionAttributeco zwraca 400zamiast 401i „jaskółki” Podstawowe okno dialogowe uwierzytelniania.

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

użyj w następujący sposób:

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

Mam nadzieję, że zaoszczędzi ci to trochę czasu.

Matas Vaitkevicius
źródło