我对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之外的其他位置?
是的,你可以简单地这样做:
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;
});