当用户登录时,他们可以存储表示其身份验证令牌的cookie.我通过调用服务来包含该令牌以检索用户的信息,其中包括他们所属的组.然后在服务中设置生成的标识,在服务中可以检索它并在应用程序的其余部分中使用它.更重要的是,路由器将使用该标识确保它们在将它们转换为请求状态之前已登录并属于相应的组.
我有这样的代码:
app .config(['$stateProvider',function($stateProvider) { // two states; one is the protected main content,the other is the sign-in screen $stateProvider .state('main',{ url: '/',data: { roles: ['Customer','Staff','Admin'] },views: {} // omitted }) .state('account.signin',{ url: '/signin',views: {} // omitted }); }]) .run(['$rootScope','$state','$http','authority','principal',function($rootScope,$state,$http,authority,principal) { $rootScope.$on('$stateChangeStart',function (event,toState) { // listen for when trying to transition states... var isAuthenticated = principal.isAuthenticated(); // check if the user is logged in if (!toState.data.roles || toState.data.roles.length == 0) return; // short circuit if the state has no role restrictions if (!principal.isInAnyRole(toState.data.roles)) { // checks to see what roles the principal is a member of event.preventDefault(); // role check Failed,so... if (isAuthenticated) $state.go('account.accessdenied'); // tell them they are accessing restricted feature else $state.go('account.signin'); // or they simply aren't logged in yet } }); $http.get('/svc/account/identity') // now,looks up the current principal .success(function(data) { authority.authorize(data); // and then stores the principal in the service (which can be injected by requiring "principal" dependency,seen above) }); // this does its job,but I need it to finish before responding to any routes/states }]);
如果我登录,导航,退出等,这一切都按预期工作.问题是,如果我在登录时刷新或删除URL,我会被发送到登录屏幕,因为身份服务呼叫没有在州改变之前完成.然而,在该调用完成之后,如果存在链接或某些东西(例如主要状态),我可以按预期继续工作,所以我几乎就在那里.
我知道您可以让状态等待在转换之前解析参数,但我不知道如何继续.
解决方法
>正如您所料,解决是启动任何异步调用并确保它们在状态转换之前完成的适当位置.
>您将希望为确保您的解析发生的所有状态创建抽象父状态,这样如果有人刷新浏览器,您的异步解析仍然发生并且您的身份验证正常工作.您可以在状态上使用父属性来创建另一个状态,否则该状态将不会被命名/点表示法继承.这有助于防止您的州名变得无法管理.
>虽然您可以将所需的任何服务注入到您的解析中,但您无法访问它尝试转换到的状态的toState或toStateParams.但是,$stateChangeStart事件将在解析之前发生.因此,您可以将事件args中的toState和toStateParams复制到$rootScope,并将$rootScope注入到您的resolve函数中.现在您可以访问它尝试转换到的状态和参数.
>一旦解决了资源,就可以使用promises进行授权检查,如果失败,可以使用$state.go()将它们发送到登录页面,或者做任何你需要做的事情.当然,有一点需要注意.
>一旦在父状态下完成解析,ui-router将不再解析它.这意味着您的安全检查不会发生!哎呀!解决方案是进行两部分检查.一旦解决,我们已经讨论过了.第二次是在$stateChangeStart事件中.这里的关键是检查并查看资源是否已解决.如果是,请执行相同的安全检查,但是在事件中.如果资源没有得到解决,那么check in resolve将会解决它.要实现此目的,您需要在服务中管理资源,以便适当地管理状态.
其他一些misc.笔记:
>不要费心将所有authz逻辑塞入$stateChangeStart.虽然您可以阻止事件并执行异步解析(在您准备好之前有效地停止更改),然后尝试在promise承诺成功处理程序中恢复状态更改,但是存在一些阻止其正常工作的问题.
>您无法更改当前状态的onEnter方法中的状态.
This plunk是一个工作的例子.