在调用REST端点之前进行身份验证

时间:2015-09-24 15:25:49

标签: javascript angularjs rest http

我尝试在调用任何其他端点之前从我的REST API获取身份验证令牌(最好是一次)。 为此,我创建了一个令牌工厂,它调用登录并返回一个令牌。然后,我希望将该令牌工厂注入我的其他控制器。我希望在从令牌工厂获取令牌之前,我的控制器会调用服务的依赖关系。我做错了什么?

工厂:

app.factory('tokenFactory', function($http, appConfig) {

    console.log('calling endpoint: ' + appConfig.REST_ENDPOINT + 'authentication/login');

    var apiToken;

    $http.post(appConfig.REST_ENDPOINT + 'authentication/login', { 
        "username": "john",
        "password": "open$esame" 
    }).
    success(function(data) {
        apiToken = data.token;
    }).
    error(function(data) {
        //
    });

    return {
        apiToken: apiToken
    };
});

控制器:

app.controller('clientListCtrl', function($scope, $http, appConfig, tokenFactory) {

    console.log('calling endpoint: ' + appConfig.REST_ENDPOINT+'/client/list');

    $http.get(appConfig.REST_ENDPOINT+'/client/list', { 
        header: { 'Authorization': tokenFactory.apiToken }
        })
        .success(function(data) {
            $scope.clients = data;    
        }).
        error(function(data, status) {
            //
        });
});

2 个答案:

答案 0 :(得分:1)

是的,您必须考虑Ajax的异步方面并利用承诺链($http.post实际上返回您需要返回的承诺)。工厂将使用方法getToken可以定义在收到结果时通知的success方法。

app.factory('tokenFactory', function($http, appConfig) {
    console.log('calling endpoint: ' + appConfig.REST_ENDPOINT + 'authentication/login');

    return {
      getToken: function() {
        return $http.post(appConfig.REST_ENDPOINT + 'authentication/login', { 
          "username": "john",
          "password": "open$esame" 
        }).
        success(function(data) {
          return data.token;
        }).
        error(function(data) {
          //
        });
      }
    };
});

那就是说,我认为你应该利用Angular的HTTP拦截器功能。这允许在请求中透明地设置安全令牌。第一次使用AJAX获取令牌,然后您可以重用此令牌。

app.factory('securityTokenInterceptor', function($q, tokenFactory) {  
  var currentToken = null;
  return {
    request: function(config) {
      if (currentToken != null) {
        config.headers['Authorization'] = currentToken;
        return config;
      }

      var deferred = $q.defer();
      tokenFactory.getToken().then(function(token) {
        config.headers['Authorization'] = token.token;
        currentToken = token.token;
        deferred.resolve(config);
      }, function(err) {
        // Handle error (reject promise, ...)
      });
      return deferred.promise;
    }
  };
})

以下是在$httpProvider上注册拦截器的方法:

app.config(function($httpProvider) {
    $httpProvider.interceptors.push('securityTokenInterceptor');
})

这是我用来获取令牌的假工厂:

app.factory('tokenFactory', function($q, $timeout) {
  return {
    getToken: function() {
      var deferred = $q.defer();
      $timeout(function() {
        deferred.resolve({token:'mytoken'});
      }, 500);
      return deferred.promise;
    }
  };
})

希望它可以帮到你, 亨利

答案 1 :(得分:0)

在您的工厂: $http.post()是异步的,因此它之后的返回将不包含来自post请求的数据。我建议你回复你从调用$http.post()获得的promise对象。

在您的控制器中:您可以使用返回的承诺并定义成功方法,您可以在其中执行获取请求。

tokenFactory.success(function (tokenData) {
  token = tokenData.token;
  $http.get(endpoint, { header: { 'auth': token } })
    .success(...)
    .error(...);
});

不确定这是否是最好的方法,但我认为它可以这样工作。