2015-06-02 24 views
5

Tôi đã tạo trang web AngularJS hoạt động với API. API này cung cấp một số tính năng như xác thực (Oauth).Vòng lặp vô hạn trong thiết bị chặn

Khi API trả về lỗi 401, điều đó có nghĩa là access_token đã hết hạn và cần được làm mới với refresh_token.

Tôi đã tạo một trình chặn trong AngularJS. Mục tiêu của nó là để kiểm tra xem kết quả trả về bởi API có phải là lỗi 401 hay không và nếu đúng như vậy, nó phải làm mới mã thông báo và sau đó, xử lý yêu cầu bị từ chối trước đó.

Vấn đề là máy đánh chặn tạo ra một vòng lặp vô hạn. Sau sự thất bại thứ hai của yêu cầu ban đầu, nó sẽ dừng lại nhưng không.

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; 

    } 

    } 

}); 

Vì vậy, mã này:

  • Bắt đầu khi yêu cầu đầu tiên thất bại
  • Làm mới token
  • Retry yêu cầu nhưng thất bại một lần nữa (< - Tôi chỉ muốn làm cho nó dừng lại ở đây)
  • Làm mới mã thông báo
  • Thử lại yêu cầu nhưng không thành công lại
  • Làm mới token
  • Retry yêu cầu nhưng thất bại một lần nữa
  • vv ...
+0

điều này không đúng: 'return deferred.promise();'. Bạn chỉ nên trả về đối tượng lời hứa 'return deferred.promise' và không cố thực thi nó. – user2943490

Trả lời

5

tôi làm việc về vấn đề này trong ứng dụng của tôi. Yêu cầu làm mới của bạn cần bao gồm biến cấu hình/tiêu đề như skipIntercept: true. Sau đó, khi bạn chặn điều này làm phản hồi không thành công, bạn có thể kiểm tra biến số rejection.config.skipIntercept. Nếu điều đó là đúng, bạn hãy đi thẳng đến $q.reject(rejection).

Nơi bạn có:

if (rejection.status == 401) { 

Thay đổi nó để:

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

Và sau đó ở trên này:

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

Bạn cần phải thêm:

 skipIntercept: true, 

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

PS. there's an existing solution bạn có thể sử dụng.

+0

Giải pháp của bạn hoạt động, tôi không có vòng lặp vô hạn nữa! Liên quan đến "giải pháp hiện tại" của bạn, nó trông tuyệt vời nhưng nó không phù hợp cho tất cả các công cụ làm mới mã thông báo, phải không? Có cách nào để thích ứng với nhu cầu của tôi không? Tôi mới đến Angular và tôi bị lạc một chút ... – Flobesst

+0

@Flobesst Hãy xem tập tin readme trên repo git, nó giải thích cách sử dụng máy đánh chặn. Về cơ bản, interceptor làm mọi thứ, ngoại trừ chính yêu cầu refresh. Bạn chỉ cần thiết lập trình xử lý sự kiện ('$ rootScope. $ On (...)') cho sự kiện mà bộ chặn đánh chặn trên 401, và sau đó kích hoạt yêu cầu làm mới của bạn, và sau đó tiến hành từ đó. – ngDeveloper

Các vấn đề liên quan