我有一个使用UI路由器的Angular应用程序,我试图在应用程序运行时验证用户的令牌(如果存在)。我还检查用户是否有权访问某些路线。问题是在我从授权端点收到响应之前$stateChangeStart
正在运行。这是一些代码(下面带有js的coffeescript) - 这都在我的run
块中。
app.run(($rootScope, $state, $stateParams, $log, Auth) ->
currentState = 'home'
$rootScope.$state = $state
# read a cookie if cookie exists
if Auth.setAuthenticationToken()
# hit api endpoint to validate token
Auth.validateToken (user) ->
# route to current state
# this returns after $stateChangeStart runs below
$state.go(currentState)
$rootScope.$on '$stateChangeStart', (event, toState, toParams, fromState, fromParams) ->
currentState = toState.name
Auth.setAuthenticationToken()
$rootScope.error = null
# compare users access permissions with incoming route's access level
if (!Auth.authorize toState.data.access, Auth.user)
event.preventDefault()
$rootScope.error = "Sorry, you haven't provided the required credentials."
$log.warn $rootScope.error
)
我的问题是如何在返回auth端点的响应后才能运行$stateChangeStart
。这只需要第一次发生。每次后续状态更改都可以在不命中auth端点的情况下完成。
答案 0 :(得分:6)
我会在Auth
服务中创建一个返回承诺的函数。之后,解决(授权)或拒绝(未授权)延期。然后在路径定义的resolve
属性
$stateProvider.state('stateName',{
...
...
resolve: {
isAuthorized: function(Auth){
return Auth.checkAuthorization();
}
}
})
为了支持后续检查,您可以在服务中维护承诺。这可能如下所示:
myApp.service('Auth',function($http,$q){
var authStatusDeferred = $q.defer();
this.checkAuthorization = function(){
return authStatusDeferred.promise;
};
this.validateToken = function(user){
var isValid = false;
//..do validation stuff
if(isValid) authStatusDeferred.resolve();
//Otherwise state change will not happen..
};
});
哦,抱歉没有咖啡
答案 1 :(得分:1)
获得用户数据后,您应该致电$urlRouter.sync()
。另外,如果未获得用户,您可能希望使用$stateChangeStart
来保护event.preventDefault()
。
答案 2 :(得分:1)
我想回答这个问题已经太晚了,但我想在这里评论可能需要一点想法的人。
我试图长时间做同样的事情而且我不再那样做了。我不认为stateChangeStart
听众可靠使用。
我认为使用$state.go
服务来装饰$provide
的最佳方式就是使用/* config your angular app */
.config(function($provide) {
$provide.decorator('$state', function($delegate) {
var myState = $delegate;
// Rename original 'go' method
myState.originalGo = myState.go;
myState.go = function(toState, toParams, options) {
/*
* Do what you want to do :)
*/
this.originalGo(toState, toParams, options);
};
return $delegate;
});
服务。这是一个例子:
$stateChangeStart
通过这种方法,您可以在String sqlStatement = "SELECT StartDate, EndDate FROM Booking between " + startD + ", " + endD;
之前做任何您想做的事情。
我希望它有所帮助。
答案 3 :(得分:1)
我找到了一种非常好的方法来使这项工作正常,而不是完全依赖于另一种答案中的决心here。这是代码:
rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState) {
if (dataService.isInitialized()) {
proceedAsUsual(); // Do the required actions based on the data you received in the service
}
else {
event.preventDefault();
dataService.intialize().success(function () {
$state.go(toState, toParams);
});
}
});
然后您可以记住,您的数据已经按照您喜欢的方式在服务中初始化,例如:
function dataService() {
var initialized = false;
return {
initialize: initialize,
isInitialized: isInitialized
}
function intialize() {
return $http.get(...)
.success(function(response) {
initialized=true;
});
}
function isInitialized() {
return initialized;
}
};