7

我一直试图让我的刷新令牌工作一段时间,我希望我已经接近了。我的令牌刷新并触发对任何导致 401 的调用的后续 200 调用,但我页面上的数据不会刷新。

当访问令牌过期时,会发生以下情况:

在此处输入图像描述

在 401 之后,GetListofCompanyNames 返回 200,其中包含使用正确更新的访问令牌的名称列表。但是,我的下拉菜单不会刷新。

我的拦截器:

  app.factory('authInterceptorService',['$q', '$location', 'localStorageService', '$injector', function($q, $location, localStorageService, $injector) {
        return {
            request: function(config) {

                config.headers = config.headers || {};

                var authData = localStorageService.get('authorizationData');
                if (authData) {
                    config.headers.Authorization = 'Bearer ' + authData.token;
                }
                return config;
            },
            responseError: function(rejection) {
                //var promise = $q.reject(rejection);
                var authService = $injector.get('authService');
                if (rejection.status === 401) {

                    // refresh the token
                    authService.refreshToken().then(function() {
                        // retry the request
                        var $http = $injector.get('$http');
                        return $http(rejection.config);
                    });
                }
                if (rejection.status === 400) {
                    authService.logOut();
                    $location.path('/login');
                }
                return $q.reject(rejection);
            }
        };
    }
]);

我关于 401 拒绝的返回声明在这里看起来很可疑,但我不确定用什么来代替它。因此我的问题是:当我拨打新电话时,如何让我的页面刷新它的数据?

更新:

当 200 返回时,这让我过去了,我可以得到一个下拉菜单来刷新,但是我失去了页面上的任何状态(例如选择的下拉菜单),如下所示。

authService.refreshToken().then(function() {
var $state = $injector.get('$state');
$state.reload();
});

回到绘图板!

4

3 回答 3

2

尝试发出你的重试呼叫$timeout,它应该可以工作。

这是更新的代码:

app.factory('authInterceptorService',['$q', '$location', 'localStorageService', '$injector', function($q, $location, localStorageService, $injector) {
        return {
            request: function(config) {

                config.headers = config.headers || {};

                var authData = localStorageService.get('authorizationData');
                if (authData) {
                    config.headers.Authorization = 'Bearer ' + authData.token;
                }
                return config;
            },
            responseError: function(rejection) {
                //var promise = $q.reject(rejection);
                var authService = $injector.get('authService');
                if (rejection.status === 401) {

                    // refresh the token
                    authService.refreshToken().then(function() {
                        // retry the request
                  return $timeout(function() {
                        var $http = $injector.get('$http');
                        return $http(rejection.config);
                    }});
                }
                if (rejection.status === 400) {
                    authService.logOut();
                    $location.path('/login');
                }
                return $q.reject(rejection);
            }
        };
    }
]);

$timeout 返回一个由函数参数返回的完成的承诺,因此我们可以方便地返回包装在 $timeout 中的 $http 调用。

谢谢。

于 2017-05-18T12:25:30.687 回答
1

我想你可能想改变你做这件事的方式。解决此问题的一种方法是将 $rootScope 注入您的authInterceptorService,然后在成功刷新令牌后,调用类似 $rootScope.broadcast('tokenRefreshed').

我不太清楚您如何设置处理下拉列表的视图和控制器,但我会为该'tokenRefreshed'事件设置一个侦听器。从这里,您可以再次调用GetListofCompanyNames. 如果您这样做,您可以轻松控制并确保模型得到更新。

于 2017-05-17T15:01:08.993 回答
0

我的最终解决方案:

app.factory('authInterceptorService', ['$q', '$location', 'localStorageService', '$injector', function($q, $location, localStorageService, $injector) {
        var $http;
        var retryHttpRequest = function(config, deferred) {
            $http = $http || $injector.get('$http');
            $http(config).then(function(response) {
                    deferred.resolve(response);
                },
                function(response) {
                    deferred.reject(response);
                });
        }

        return {
            request: function(config) {

                config.headers = config.headers || {};

                var authData = localStorageService.get('authorizationData');
                if (authData) {
                    config.headers.Authorization = 'Bearer ' + authData.token;
                }
                return config;
            },
            responseError: function(rejection) {
                var deferred = $q.defer();
                if (rejection.status === 401) {
                    var authService = $injector.get('authService');
                    authService.refreshToken().then(function() {
                            retryHttpRequest(rejection.config, deferred);
                        },
                        function () {
                            authService.logOut();
                            $location.path('/login');
                            deferred.reject(rejection);
                        });
                } else {
                    deferred.reject(rejection);
                }
                return deferred.promise;
            }
        };
    }
]);

从https://github.com/tjoudeh/AngularJSAuthentication/blob/master/AngularJSAuthentication.Web/app/services/authInterceptorService.js几乎一对一地复制。

这个透明地处理所有请求并在必要时刷新它们。它会在刷新令牌过期时注销用户,并通过正确拒绝将错误传递给控制器​​。但是,它似乎不适用于多个飞行中的请求,当我在我的系统中获得它的用例时,我会研究它。

于 2017-05-22T14:47:41.057 回答