【问题标题】:How to refresh expired jwt token in AngularJS如何在AngularJS中刷新过期的jwt令牌
【发布时间】:2017-11-28 09:43:14
【问题描述】:

我正在开发一个 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 错误(令牌已过期)并要求另一个令牌,但这是不可能的,因为据我所知,无法在 .config 中注入服务。配置块:

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,我尝试简单地重新加载页面,但这不是最佳选择,因为用户看到网络正在刷新并且他丢失了为请求插入的所有数据。

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

【问题讨论】:

    标签: angularjs jwt


    【解决方案1】:

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

    看来您已经在使用$injector 即时注入$http-service,因此为了解决您的循环依赖,使用相同的方法注入您的TokenService 可能会解决您的问题。

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

    我之前也遇到过同样的问题,如果有什么帮助可以check my solution on GitHub

    【讨论】:

    • 非常感谢您的帮助。我应用了你说的。现在的问题是,当我在 ResponseError 中调用 getToken 时:它返回新令牌,但并未将其应用于当前的 401 请求,因此我收到了新令牌,但对 API 的请求仍然失败。我正在 GitHub 上阅读您的解决方案,我希望我可以用该代码解决它。非常感谢!
    • 我终于以你的工厂为例修改了我的代码。它工作得很好!谢谢!
    猜你喜欢
    • 1970-01-01
    • 2019-02-11
    • 1970-01-01
    • 2015-05-19
    • 2019-07-04
    • 2018-07-22
    • 1970-01-01
    • 1970-01-01
    • 2018-08-05
    相关资源
    最近更新 更多