2014-06-09 8 views
24

Sto costruendo un'app web AngularJS (1.2.16) con un'API RESTful e desidero inviare 401 risposte non autorizzate per le richieste in cui le informazioni di autenticazione non sono valide o non sono presenti. Quando lo faccio, anche con un intercettore HTTP presente, vedo la finestra di dialogo "Autenticazione richiesta" di base del browser quando una richiesta AJAX viene effettuata tramite AngularJS. Il mio intercettore corre dopo il in quella finestra di dialogo, che è troppo tardi per fare qualcosa di utile.Prevenire la finestra di dialogo di autenticazione HTTP utilizzando AngularJS Interceptors

Un esempio concreto:

mio backend API restituisce 401 per /api/things a meno che un token di autorizzazione è presente. Bello e semplice

Sul lato app AngularJS, ho guardato il docs e impostare un intercettore come questo nel config blocco:

$httpProvider.interceptors.push(['$q', function ($q) { 
    return { 
    'responseError': function (rejection) { 
     if (rejection.status === 401) { 
     console.log('Got a 401') 
     } 
     return $q.reject(rejection) 
    } 
    } 
}]) 

Quando carico la mia app, rimuovere il token di autenticazione, ed eseguire un AJAX chiamata a /api/things (si spera innescare l'intercettore sopra), vedo questo:

Authentication Required

Se cancello che finestra, vedo il console.log uscita "Ha ottenuto un 401" che speravo di vedere invece di quel dialogo:

Got a 401

Chiaramente, l'intercettore sta lavorando, ma è intercettare troppo tardi!

Vedo numerosi messaggi sul Web relativi all'autenticazione con AngularJS in situazioni come questa, e tutti sembrano utilizzare intercettori HTTP, ma nessuno di loro menziona la finestra di dialogo di autenticazione di base. Alcuni pensieri errati che ho avuto per la sua comparsa inclusi:

  • Manca l'intestazione Content-Type: application/json sulla risposta? No, è lì.
  • È necessario restituire qualcosa di diverso dalla promessa di rifiuto? Questo codice viene sempre eseguito dopo la finestra di dialogo, indipendentemente da ciò che viene restituito.

Mi manca qualche passaggio di configurazione o uso l'intercettore in modo errato?

+0

Perché non hai usato 403 anziché 401? –

+0

Ho usato un 401 perché, nella domanda originale, ho rimosso il token di autenticazione (nel mio caso, un cookie). 401 è il codice di risposta corretto da utilizzare qui perché la richiesta richiede l'autenticazione e nessuno è stato fornito. 403 è per quando viene fornita l'autenticazione ma il server nega l'accesso alla risorsa. –

risposta

12

Capito!

Il trucco era inviare un'intestazione di risposta WWW-Authenticate di un valore diverso da Basic. È quindi possibile acquisire il 401 con un intercettore di base $http o qualcosa di ancora più intelligente come angular-http-auth.

+6

Potresti approfondire per favore? "Qualcosa di ancora più intelligente come angular-http-auth" richiede che il server invii una risposta di 200. Sto cercando una soluzione in cui il server restituisce un codice 401. – Romain

+0

Penso che sia solo popup quando 'Autorizzazione': 'Base XXX' – killebytes

+0

si prega di inviare qualche esempio di codice Sto avendo lo stesso problema. La richiesta di autorizzazione di base IOS non termina mai –

1

Per riferimento futuro

mi è venuta in mente questa soluzione quando si cerca di gestire 401 errori. Non ho avuto la possibilità di riscrivere Basic a x-Basic o qualcosa di simile, quindi ho deciso di gestirlo sul lato client con Angular.

Quando si avvia un logout, provare prima a effettuare una richiesta errata con un utente falso per eliminare le credenziali attualmente memorizzate nella cache.

Ho questa funzione di fare le richieste (che sta utilizzando le chiamate asynch disabili di $.ajax con jQuery):

function authenticateUser(username, hash) { 
    var result = false; 
    var encoded = btoa(username + ':' + hash); 

    $.ajax({ 
     type: "POST", 
     beforeSend: function (request) { 
      request.setRequestHeader("Authorization", 'Basic ' + encoded); 
     }, 
     url: "user/current", 
     statusCode: { 
      401: function() { 
       result = false; 
      }, 
      200: function (response) { 
       result = response; 
      } 
     }, 
     async: false 
    }); 

    return result; 
} 

Così, quando provo ad accedere un utente fuori, questo accade:

//This will send a request with a non-existant user. 
//The purpose is to overwrite the cached data with something else 
accountServices.authenticateUser('logout','logout'); 

//Since setting headers.common.Authorization = '' will still send some 
//kind of auth data, I've redefined the headers.common object to get 
//rid of the Authorization property 
$http.defaults.headers.common = {Accept: "application/json, text/plain, */*"}; 
8

I ha riscontrato questo problema insieme a Spring Boot Security (HTTP basic), e dal momento che Angular 1.3 è necessario impostare $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest'; affinché il popup non venga visualizzato.

+1

non funziona per la mia app con Angular 1.5 e firefox 48.x ... il prompt di autenticazione di base viene attivato anche con X-Requested-With header ... – ptitjuju69

+0

Lo stesso per me. Ho aggiunto questa intestazione in postman. ma non funziona –

+1

questo è risolto il mio problema. la modal di autenticazione del browser è stata nascosta dopo aver applicato il problema. Grazie. – luffy

Problemi correlati