如何在AngularJS中刷新过期的jwt标记

时间:2017-06-25 08:38:34

标签: angularjs jwt

我正在开发一个Angular webapp,它使用API​​来获取一些数据。 要获得该数据,我必须发送JWT。 我创建了一个调用PHP文件的服务来获取令牌:

(function () {
'use strict';

angular
.module('MyApp')
.factory('TokenService', Service);

function Service( $http, $localStorage ) {

    var service = {};

    service.getToken = getToken;

    return service;

    function getToken() {
        return $http.post('gettoken.php');
    }
}})();

我所做的就是在.run块我调用它并存储收到的令牌:

function run( $rootScope, $http, $location, $localStorage, TokenService ) {
    TokenService.getToken().then(function(response) {
        $localStorage.token = response.data.token;
    });
    console.log('token: ' + $localStorage.token);
    $http.defaults.headers.common.Authorization = 'Bearer ' + $localStorage.token;
}})();

令牌到期每隔几分钟,所以我必须请求另一个令牌,以便用户继续与API交互。

要解决这个问题,我的第一种方法是使用.config块拦截401错误(令牌已过期)并要求另一个令牌,但这是不可能的,因为据我所知,无法注入服务。配置块:

function config2( $httpProvider ) {
    $httpProvider.interceptors.push(function ($q, $rootScope) {
        return {
            'response': function (response) {
            //Will only be called for HTTP up to 300
            console.log(response);
            return response;
        },
        'responseError': function (rejection) {
            if(rejection.status === 401) {
                var deferred = $q.defer();
                TokenService.getToken(function() {
                    retryHttpRequest(response.config, deferred);
                });
                return deferred.promise;
            } else {
                return response;
            }
            function retryHttpRequest(config, deferred){
              function successCallback(response){
                deferred.resolve(response);
              }
              function errorCallback(response){
                deferred.reject(response);
              }
              var $http = $injector.get('$http');
              $http(config).then(successCallback, errorCallback);
            }
        }
    };
});
}

实际上,当我执行webapp时,它表示没有定义TokenService,如果我注入了TokenService,显然它会创建一个循环依赖:

    angular.js:66 Uncaught Error: [$injector:cdep] Circular dependency found: $http <- TokenService <- $http <- $templateRequest <- $route
http://errors.angularjs.org/1.6.4/$injector/cdep?p0=%24http%20%3C-%20TokenService%20%3C-%20%24http%20%3C-%20%24templateRequest%20%3C-%20%24route
    at angular.js:66
    at getService (angular.js:4936)
    at injectionArgs (angular.js:4969)
    at Object.invoke (angular.js:4995)
    at Object.enforcedReturnValue [as $get] (angular.js:4836)
    at Object.invoke (angular.js:5003)
    at angular.js:4795
    at getService (angular.js:4944)
    at injectionArgs (angular.js:4969)
    at Object.invoke (angular.js:4995)

这是一个非常愚蠢的情况,但我花了一整天的时间来寻找最佳解决方案。 一旦拦截器检测到401 responseError,我就试图简单地重新加载页面,但这不是最佳的,因为用户看到网页刷新并且他丢失了为请求插入的所有数据。

如果你们中的任何一个人不得不处理这类问题并且可以分享任何方法来解决它,那就太好了。

1 个答案:

答案 0 :(得分:1)

这可能是因为$http服务取决于您的拦截器,您的TokenService取决于$http服务,而您的拦截器取决于TokenService。这会导致循环依赖。

看来你已经在使用$injector及时注入$ http-service,所以要解决你的循环依赖,使用相同的方法注入你的TokenService可能会解决你的问题。

var TokenService = $injector.get('TokenService');

之前我偶然发现了同样的问题,所以如果有任何帮助你可以check my solution on GitHub