我在Angular.js中实现了一些简单的客户端身份验证逻辑。涉及的页面是:
/account#/login (public)
/account (require login)
/account#/settings (require login)
当用户未登录并尝试访问/account
或/account/#/settings
时,该应用应该重定向到登录页面。
我使用ui-router配置了以下路由:
$stateProvider
.state('overview', {
url: '/',
restricted: true
})
.state('settings', {
url: '/settings',
restricted: true
})
.state('login', {
url: '/login',
restricted: false
})
并且在URL更改时,我检查即将到来的页面是否是受限页面以及当前用户是否未登录。如果是,则重定向到登录。
app.run(function($rootScope, $location, $state, auth) {
$rootScope.$on('$stateChangeStart', function(event, next) {
if (next.restricted && !auth.isLoggedIn()) {
event.preventDefault();
$state.go('login');
}
});
});
auth
只是一项检查登录状态并返回true
(已登录)或false
(未登录)的服务。
这是我的问题:
即使这种(有点)有效,但在未登录时尝试访问受限制的页面时,我看到页面闪烁问题。在重定向到登录页面之前,页面会快速闪烁受限页面的内容。
我在线进行了一些研究,有些人提到潜在的解决方案可能在定义状态时使用resolve
,因为除非成功解析,否则页面不会加载。但是,当我尝试添加
resolve: {
load: function(auth) {
return auth.isLoggedIn();
}
}
它没有用。我错过了什么?是否正在使用resolve
?
答案 0 :(得分:2)
您目前的工作方式是检查用户是否已登录,并将load
设置为true
或false
。在load
被解析之前,控制器也会被实例化,这就是你看到闪烁的原因。你需要在这里完成两件事:
load
。对于第一部分,我们需要使用promise,因为它将被解析并在实例化控制器之前转换为值。这就是文档所说的内容:
如果这些依赖项中的任何一个是承诺,它们将被解析并且 转换为控制器实例化之前的值和 $ stateChangeSuccess事件被触发。
以下代码可以为我们做到这一点:
var isLoggedin = ['auth', '$q',
function(auth, $q) {
var deferred = $q.defer();
//assuming auth.isLoggedIn returns a promise
var loginPromise = auth.isLoggedIn();
loginPromise.then(
function(response) {
deferred.resolve(response);
},
function(error) {
deferred.reject('Not logged in');
});
return deferred.promise;
}
];
状态将使用isLoggedin
:
$stateProvider
.state('overview', {
url: '/',
resolve: {
loggedin: isLoggedin
}
})
.state('settings', {
url: '/settings',
resolve: {
loggedin: isLoggedin
}
})
.state('login', {
url: '/login'
})
对于第二个问题,即将用户重定向到登录页面,您可以监听在未解决状态时触发的$stateChangeError
事件,并使用$state.go
重定向用户。