Come posso sopprimere la finestra di dialogo di autenticazione del browser?


85

La mia applicazione web ha una pagina di accesso che invia le credenziali di autenticazione tramite una chiamata AJAX. Se l'utente inserisce il nome utente e la password corretti, va tutto bene, ma in caso contrario, accade quanto segue:

  1. Il server Web determina che, sebbene la richiesta includesse un'intestazione di autorizzazione ben formata, le credenziali nell'intestazione non vengono autenticate correttamente.
  2. Il server web restituisce un codice di stato 401 e include una o più intestazioni WWW-Authenticate che elencano i tipi di autenticazione supportati.
  3. Il browser rileva che la risposta alla mia chiamata sull'oggetto XMLHttpRequest è un 401 e la risposta include le intestazioni WWW-Authenticate. Quindi si apre una finestra di dialogo di autenticazione che chiede, di nuovo, il nome utente e la password.

Va tutto bene fino al passaggio 3. Non voglio che la finestra di dialogo venga visualizzata, voglio gestire la risposta 401 nella mia funzione di callback AJAX. (Ad esempio, visualizzando un messaggio di errore nella pagina di accesso.) Voglio che l'utente inserisca nuovamente il nome utente e la password, ovviamente, ma voglio che vedano il mio modulo di accesso amichevole e rassicurante, non il brutto, predefinito del browser finestra di dialogo di autenticazione.

Per inciso, non ho alcun controllo sul server, quindi fargli restituire un codice di stato personalizzato (cioè qualcosa di diverso da un 401) non è un'opzione.

C'è un modo per sopprimere la finestra di dialogo di autenticazione? In particolare, posso sopprimere la finestra di dialogo Autenticazione richiesta in Firefox 2 o versioni successive? Esiste un modo per sopprimere la finestra di dialogo Connetti a [host] in IE 6 e versioni successive?


Modifica
Informazioni aggiuntive dall'autore (18 settembre):
dovrei aggiungere che il vero problema con la finestra di dialogo di autenticazione del browser che si apre è che fornisce informazioni insufficienti all'utente.

L'utente ha appena inserito un nome utente e una password tramite il modulo nella pagina di accesso, crede di averli digitati entrambi correttamente e ha fatto clic sul pulsante di invio o di invio. La sua aspettativa è che venga portato alla pagina successiva o forse gli venga detto che ha inserito le sue informazioni in modo errato e che dovrebbe riprovare. Tuttavia, gli viene invece presentata una finestra di dialogo inaspettata.

La finestra di dialogo fa nessun riconoscimento del fatto che ha appena fatto inserire un nome utente e una password. Non indica chiaramente che si è verificato un problema e che dovrebbe riprovare. Invece, la finestra di dialogo presenta all'utente informazioni criptiche come "Il sito dice: ' [realm] '." Dove [realm] è un nome di reame breve che solo un programmatore potrebbe amare.

I progettisti di Web Broswer prendono nota: nessuno chiederebbe come sopprimere la finestra di dialogo di autenticazione se la finestra di dialogo stessa fosse semplicemente più user-friendly. L' intera ragione per cui sto compilando un modulo di accesso è che il nostro team di gestione del prodotto considera giustamente orribili le finestre di dialogo di autenticazione dei browser.


1
La risposta è che non esiste una buona risposta. Gli hack suggeriti da Marijn sono il più vicini possibile. Ovviamente, utilizzando un'autenticazione personalizzata compresa dal server e dal tuo JavaScript, ma non dal browser, farà anche il trucco, se possibile.
dgvid

Sono stato allo stesso problema e ho trovato questo link in un commento qui su stackoverflow (non il mio blog): loudvchar.blogspot.ca/2010/11/… Spero che ti possa aiutare.
gies0r

Risposte:


17

Non penso sia possibile: se utilizzi l'implementazione del client HTTP del browser, verrà sempre visualizzata quella finestra di dialogo. Mi vengono in mente due hack:

  1. Forse Flash gestisce questo in modo diverso (non ho ancora provato), quindi avere un filmato in flash che fa la richiesta potrebbe aiutare.

  2. Puoi impostare un "proxy" per il servizio a cui stai accedendo sul tuo server e fare in modo che modifichi un po 'le intestazioni di autenticazione, in modo che il browser non le riconosca.


"Non possibile" sembra essere la risposta corretta, anche se sospetto che l'hack "proxy" farebbe il trucco.
dgvid

@Stobor La risposta accettata per il duplicato che hai pubblicato in realtà rimanda a questa domanda come risposta!
8bitjunkie

3
@ 7SpecialGems Buona cattura. Non stavo suggerendo che fosse uno stupido, ho collegato alla risposta specifica (quella WWW-Authenticate) che è stata pubblicata 4 anni dopo la risposta accettata. Anche se col senno di poi, non riesco a ricordare perché lo stavo guardando o come l'ho testato.
Stobor

1
Provo a rilevare un errore 401 non autorizzato con questo codice: $ .ajaxSetup ({statusCode: {401: function () {RedirectToLogin ();}}}); Ma IE mostra sempre la finestra di dialogo di autenticazione del browser. Come posso sopprimere questa finestra di dialogo in ASP.Net MVC 2?
PaulP

@PaulP, come è stato detto, hai bisogno di un proxy che rimuova le risposte del codice di stato 401 dall'intestazione WWW-Authenticate, o una sorta di implementazione del server personalizzato.
Motes

51

Ho riscontrato lo stesso problema qui e l'ingegnere di backend della mia azienda ha implementato un comportamento che apparentemente è considerato una buona pratica: quando una chiamata a un URL restituisce un 401, se il client ha impostato l'intestazione X-Requested-With: XMLHttpRequest, il server rilascia l' www-authenticateintestazione nella sua risposta.

L'effetto collaterale è che il popup di autenticazione predefinito non viene visualizzato.

Assicurati che la tua chiamata API abbia l' X-Requested-Withintestazione impostata su XMLHttpRequest. Se è così non c'è niente da fare se non cambiare il comportamento del server secondo questa buona pratica ...


3
Se il backend è basato su Java / Spring, DelegatingAuthenticationEntryPointgestisce questo comportamento per te.
Derek Slife

Grazie per questo. Molte biblioteche hanno adottato questo comportamento tra cui
Devise

1
qualche idea su come farlo in nginx? "quando una chiamata a un URL restituisce un 401, se il client ha impostato l'intestazione X-Requested-With: XMLHttpRequest, il server rilascia l'intestazione www-authenticate nella sua risposta."
markmnl

18

Il browser visualizza una richiesta di accesso quando vengono soddisfatte entrambe le seguenti condizioni:

  1. Lo stato HTTP è 4xx
  2. WWW-Authenticate l'intestazione è presente nella risposta

Se puoi controllare la risposta HTTP, puoi rimuovere l' WWW-Authenticateintestazione dalla risposta e il browser non farà apparire la finestra di dialogo di accesso.

Se non puoi controllare la risposta, puoi configurare un proxy per filtrare l' WWW-Authenticateintestazione dalla risposta.

Per quanto ne so (sentiti libero di correggermi se sbaglio), non c'è modo di impedire il prompt di accesso una volta che il browser riceve l' WWW-Authenticateintestazione.


Buone informazioni. Per quanto riguarda validi WWW-Authenticatevalori di intestazione, vedere stackoverflow.com/a/1748451/225217
Brice Roncace

6

Mi rendo conto che questa domanda e le sue risposte sono molto antiche. Ma sono finito qui. Forse lo faranno anche altri.

Se hai accesso al codice per il servizio web che sta restituendo il 401. Cambia semplicemente il servizio per restituire un 403 (Forbidden) in questa situazione invece di 401. Il browser non chiederà le credenziali in risposta a un 403. 403 è il codice corretto per un utente autenticato che non è autorizzato per una risorsa specifica. Che sembra essere la situazione del PO.

Dal documento IETF su 403:

Un server che riceve credenziali valide non adeguate per ottenere l'accesso dovrebbe rispondere con il codice di stato 403 (Forbidden)


4

In Mozilla puoi ottenerlo con il seguente script quando crei l'oggetto XMLHttpRequest:

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

La seconda riga impedisce la finestra di dialogo ....


1
Questo sembra non fare nulla in Firefox 2. Risulta in un errore di sicurezza DOM, NS_ERROR_DOM_SECURITY_ERR codice 1000, in Firefox 3.
dgvid

2

Quale tecnologia server utilizzi e c'è un particolare prodotto che utilizzi per l'autenticazione?

Poiché il browser sta solo facendo il suo lavoro, credo che tu debba cambiare le cose sul lato server per non restituire un codice di stato 401. Ciò potrebbe essere fatto utilizzando moduli di autenticazione personalizzati che restituiscono semplicemente il modulo quando l'autenticazione fallisce.


2

In Mozilla Land, l'impostazione del parametro mozBackgroundRequest di XMLHttpRequest ( docs ) su true sopprime queste finestre di dialogo e fa semplicemente fallire le richieste. Tuttavia, non so quanto sia buono il supporto cross-browser (incluso se la qualità delle informazioni sull'errore su quelle richieste non riuscite è molto buona su tutti i browser).


Il prefisso moz- non implica alcun supporto cross-browser (a meno che non sia possibile trovare parametri simili che funzionano in ciascuno degli altri browser).
Brilliand

2

jan.vdbergh ha la verità, se puoi cambiare il 401 sul lato server per un altro codice di stato, il browser non cattura e dipinge il pop-up. Un'altra soluzione potrebbe essere cambiare l'intestazione WWW-Authenticate per un'altra intestazione personalizzata. Non credo perché i diversi browser non possano supportarlo, in alcune versioni di Firefox possiamo fare la richiesta xhr con mozBackgroundRequest, ma negli altri browser ?? qui c'è un collegamento interessante con questo problema in Chromium.


1

Ho lo stesso problema con MVC 5 e VPN in cui ogni volta che siamo al di fuori della DMZ utilizzando la VPN, ci troviamo a dover rispondere a questo messaggio del browser. Utilizzando .net gestisco semplicemente l'instradamento dell'errore utilizzando

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

finora ha funzionato perché l'azione Index sotto il controller home convalida l'utente. La vista in questa azione, se l'accesso non riesce, ha controlli di accesso che utilizzo per accedere all'utente utilizzando la query LDAP passata ai servizi di directory:

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

Anche se finora ha funzionato bene, devo farti sapere che lo sto ancora testando e il codice sopra non ha avuto motivo di essere eseguito, quindi è soggetto a rimozione ... il test attualmente include il tentativo di scoprire un caso in cui il secondo set di codice è più utile. Ancora una volta, questo è un lavoro in corso, ma poiché potrebbe essere di aiuto o stimolare il cervello per alcune idee, ho deciso di aggiungerlo ora ... Lo aggiornerò con i risultati finali una volta che tutti i test saranno stati completati.


1

Sto usando Node, Express e Passport e stavo lottando con lo stesso problema. L'ho fatto funzionare impostando esplicitamente l' www-authenticateintestazione su una stringa vuota. Nel mio caso, sembrava così:

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

Spero che aiuti qualcuno!


0

Per coloro che non utilizzano C #, ecco ActionAttributeche restituisce 400invece di 401e "inghiotte" la finestra di dialogo di autenticazione di base.

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

utilizzare come segue:

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

Spero che questo ti faccia risparmiare tempo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.