2

我对 Angular 很陌生。我在我的 Angular 应用程序中使用令牌身份验证。我使用 HTTP 拦截器来检查我的后端何时返回 401,然后使用刷新令牌进行登录:

myapp.config(...)
...
$httpProvider.interceptors.push(['$q', '$injector', function($q, $injector) {
  var sessionRecoverer = {
    responseError: function(response) {
      // Session has expired
      if (response.status === 401) {
        var $http = $injector.get('$http');
        var deferred = $q.defer();
        var $auth = $injector.get('$auth');

        $auth.login({
          refresh_token: ????,
          grant_type: 'refresh_token',
          event_client: 'client',
          client_id: 'id'
        });

        // When the session recovered, make the same backend call again and chain the request
        return deferred.promise.then(function() {
          return $http(response.config);
        });
      }
      return $q.reject(response);
    }
  };
  return sessionRecoverer;
}]);

现在,refresh_token 来自我的登录控制器(它从 api 后端提取它)。所以控制器必须以某种方式将它传递给拦截器。问题是拦截器位于配置块中,因此没有服务、值等 - 只有提供者。但是提供者不能注入到控制器中。那么有没有办法将数据从控制器传递到app.config?如果没有,是否有解决方法?注入器可以在 app.config 以外的任何地方吗?

4

1 回答 1

1

是的,您可以像这样简单地做到这一点:

    myapp.config(...)
    ...
    $httpProvider.interceptors.push(['$q', '$injector', function($q, $injector, TokenFactory) {
      var sessionRecoverer = {
        responseError: function(response) {
          // Session has expired
          if (response.status === 401) {
            var $http = $injector.get('$http');
            var deferred = $q.defer();
            var $auth = $injector.get('$auth');

            $auth.login({
              refresh_token: TokenFactory.getRefreshToken(),
              grant_type: 'refresh_token',
              event_client: 'client',
              client_id: 'id'
            });

            // When the session recovered, make the same backend call again and chain the request
            return deferred.promise.then(function() {
              return $http(response.config);
            });
          }
          return $q.reject(response);
        }
      };
      return sessionRecoverer;
    }]);

正如您所说,块配置只能注入提供程序,但拦截器本身是一个工厂,因此您可以注入其他工厂,例如,一个名为 TokenFactory 的工厂应该提供一个在需要时返回刷新令牌的方法。

编辑

如果 refresh_token 是来自后端的东西,并且您想从登录控制器在 TokenFactory 中设置一个值,则可以执行以下操作来实现您的工厂和控制器:

myapp.factory('TokenFactory',function(){

  var currentRefreshToken;

  return {
    setRefreshToken: function(token){
      currentRefreshToken = token;
    },
    getRefreshToken: function(){
      return currentRefreshToken:
    }
  };
});

myapp.controller('MyLoginCtrl',function($scope,TokenFactory,$http){

  $scope.login = function(){
    $http.post('http://myapp.com/refreshtoken',$scope.credentials)
      .then(TokenFactory.setRefreshToken)
      .then(function(){ /* ... */})
      .catch(function(err){ console.error(err) })
    ;
  };

});

数据持久性

如果你想让你的令牌持久化,你可以编写一个使用 的工厂,LocalStorage HTML5 API并在你的TokenFactory:

myapp.factory('TokenFactory',function(LocalStorage){

  // load the value from localstorage (hard disk) on app starts
  var currentRefreshToken = LocalStorage.get('myapp.currentRefreshToken');

  return {
    setRefreshToken: function(token){
      currentRefreshToken = token; // save value in RAM
      LocalStorage.set('myapp.currentRefreshToken',token); // and sync the localstorage value
    },
    getRefreshToken: function(){
      return currentRefreshToken; // quick access to the value from RAM
    }
  };
});

myapp.factory('LocalStorage',function($window) {

    var localStorage = {};

    localStorage.set = function(key, value) {
        $window.localStorage[key] = value;
    };
    localStorage.get = function(key, defaultValue) {
        return $window.localStorage[key] || defaultValue;
    };
    localStorage.setObject = function(key, value) {
        $window.localStorage[key] = JSON.stringify(value);
    };
    localStorage.getObject = function(key) {
        return (!$window.localStorage[key] || $window.localStorage[key] === undefined) ? {} : JSON.parse($window.localStorage[key]);
    };
    localStorage.setArray = function(key, array){
        if (!array.length) {
            console.debug(array);
            $window.localStorage[key] = '[]';
        } else{
            this.setObject(key, array);                    
        }
    };
    localStorage.getArray = function(key){
        return (!$window.localStorage[key] || $window.localStorage[key] === undefined) ? [] : JSON.parse($window.localStorage[key]);
    };
    localStorage.exportAsFile = function(key, fileName){        
        var data = [$window.localStorage[key]] || ['{}'];
        var blob = new Blob(data,{type:'application/json;charset=utf-8'});
        $window.saveAs(blob,fileName);
    };
    return localStorage;
});
于 2015-11-12T16:21:48.493 回答