2015-06-02 4 views
5

Ich habe eine AngularJS Website mit einer API arbeiten gemacht. Diese API bietet einige Funktionen wie die Authentifizierung (Oauth). Wenn die API einen 401-Fehler zurückgibt, bedeutet dies, dass die access_token abgelaufen ist und mit der refresh_token aktualisiert werden muss.Unendliche Schleife im Interceptor

Ich habe einen Interceptor in AngularJS erstellt. Das Ziel besteht darin, zu überprüfen, ob das von der API zurückgegebene Ergebnis ein 401-Fehler ist, und falls dies der Fall ist, muss das Token aktualisiert und anschließend die vorherige abgelehnte Anforderung verarbeitet werden.

Das Problem ist, dass der Interceptor eine Endlosschleife erstellt. Nach dem zweiten Fehler der ersten Anfrage sollte es aufhören, tut es aber nicht.

angular.module('myApp') 
.factory('authInterceptor', function ($rootScope, $q, $window, $injector) { 

    return { 

    // If the API returns an error 
    'responseError' : function(rejection) { 

     // If it's a 401 
     if (rejection.status == 401) { 

     var deferred = $q.defer(); 

     $injector.get('$http').post('http://my-api.local/api/oauth/token', { 
      grant_type : 'refresh_token', 
      client_id  : 'id', 
      client_secret : 'secret', 
      refresh_token : $window.sessionStorage.refresh_token 
     }, { 
      headers : { 
      'Content-Type' : 'application/x-www-form-urlencoded' 
      }, 
      transformRequest : function(obj) { 
      var str = []; 
      for(var p in obj) 
      str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); 
      return str.join("&"); 
      } 
     }) 
     // New token request successfull 
     .success(function(refreshResponse) { 

      // Processing the failed request again (should fail again because I didn't saved the new tokens) 
      $injector.get('$http')(rejection.config).success(function(data) { 

      deferred.resolve(data); 

      }) 
      .error(function(error, status) { 

      deferred.reject(); 

      }); 

      return deferred.promise(); 

     }) 
     // New token request failure 
     .error(function(error, status) { 

      deferred.reject(); 
      // $location.path('users/login'); 

      return; 

     }); 

     } 
     // If it's another errorenter code here 
     else 
     return rejection; 

    } 

    } 

}); 

Also dieser Code:

  • beginnt, wenn die erste Anforderung fehlschlägt
  • den Token Erfrischt
  • Retries die Anfrage aber nicht wieder (< - ich habe es nur hier aufhören machen will)
  • Aktualisiert das Token
  • Wiederholt die Anforderung, schlägt aber erneut fehl
  • frischt den Token
  • Retries die Anfrage aber nicht wieder
  • etc ...
+0

das sieht nicht richtig aus: 'return deferred.promise();'. Sie sollten nur das Promise-Objekt 'return deferred.promise' zurückgeben und nicht versuchen, es auszuführen. – user2943490

Antwort

5

ich dies in meiner App gearbeitet. Ihre Aktualisierungsanforderung muss eine Konfigurations-/Header-Variable wie skipIntercept: true enthalten. Wenn Sie dies als fehlgeschlagene Antwort abfangen, können Sie die Variable rejection.config.skipIntercept überprüfen. Wenn es wahr ist, gehen Sie direkt zu $q.reject(rejection).

Wo Sie haben:

if (rejection.status == 401) { 

Ändern Sie es an:

if (rejection.status == 401 && !rejection.config.skipIntercept) { 

Und dann darüber:

 headers : { 
     'Content-Type' : 'application/x-www-form-urlencoded' 
    }, 

Sie müssen hinzufügen:

 skipIntercept: true, 

    headers: { 
     'Content-Type' : 'application/x-www-form-urlencoded' 
    }, 

PS. there's an existing solution können Sie verwenden.

+0

Deine Lösung funktioniert, ich habe keine unendlichen Schleifen mehr! Was deine "existierende Lösung" angeht, sieht sie gut aus, aber sie ist nicht für alle erfrischenden Token-Sachen geeignet, oder? Gibt es eine Möglichkeit, es an meine Bedürfnisse anzupassen? Ich bin neu bei Angular und bin ein wenig verloren ... – Flobesst

+0

@Flobesst Schau dir die Readme-Datei auf dem Git Repo an, sie erklärt, wie man den Interceptor benutzt. Im Grunde genommen erledigt der Interceptor alles, außer der Refresh-Anfrage selbst. Sie müssen lediglich einen Ereignis-Listener ('$ rootScope. $ On (...)') für das Ereignis einrichten, das der Interceptor auf eine 401 auslöst, und dann Ihre Refresh-Anfrage auslösen und dann von dort fortfahren. – ngDeveloper