8

我制作了一个使用 API 的 AngularJS 网站。此 API 提供了一些功能,例如身份验证 (Oauth)。

当 API 返回 401 错误时,表示access_token已经过期,需要用refresh_token.

我在 AngularJS 中创建了一个拦截器。它的目标是检查 API 返回的结果是否为 401 错误,如果是,则必须刷新令牌,然后处理先前被拒绝的请求。

问题是拦截器创建了一个无限循环。在初始请求第二次失败后,它应该停止但它没有。

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;

    }

  }

});

所以这段代码:

  • 在第一个请求失败时开始
  • 刷新令牌
  • 重试请求但再次失败(<-我只想让它停在这里)
  • 刷新令牌
  • 重试请求但再次失败
  • 刷新令牌
  • 重试请求但再次失败
  • ETC...
4

1 回答 1

6

我在我的应用程序中处理了这个问题。您的刷新请求需要包含一个 config/header 变量,例如skipIntercept: true. 然后,当您将此作为失败响应拦截时,您可以检查rejection.config.skipIntercept变量。如果是真的,你直接去$q.reject(rejection)

你在哪里:

if (rejection.status == 401) {

将其更改为:

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

然后在此之上:

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

您需要添加:

     skipIntercept: true,

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

PS。您可以使用现有的解决方案。

于 2015-06-02T23:48:05.920 回答