Javascript 在运行应用程序并切换到路由或状态之前解析$http请求

Javascript 在运行应用程序并切换到路由或状态之前解析$http请求,javascript,angularjs,angular-ui-router,angular-routing,Javascript,Angularjs,Angular Ui Router,Angular Routing,我已经编写了一个应用程序,在处理路由之前,我需要在应用程序运行时检索当前登录用户的信息。我使用它来支持多个/嵌套视图,并提供更丰富、有状态的路由 当用户登录时,他们可能会存储表示其身份验证令牌的cookie。我将该令牌包括在对服务的调用中,以检索用户的信息,其中包括他们所属的组。然后在服务中设置生成的标识,可以在应用程序的其余部分检索和使用该标识。更重要的是,路由器将使用该标识确保它们已登录并属于适当的组,然后再将它们转换为请求的状态 我有这样的代码: app .config(['$st

我已经编写了一个应用程序,在处理路由之前,我需要在应用程序运行时检索当前登录用户的信息。我使用它来支持多个/嵌套视图,并提供更丰富、有状态的路由

当用户登录时,他们可能会存储表示其身份验证令牌的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,我会被发送到登录屏幕,因为身份服务调用在状态更改之前尚未完成。不过,在该调用完成后,如果存在指向
main
状态的链接或其他内容,我可以继续按预期工作,所以我就快到了


我知道您可以让状态在转换之前等待解析参数,但我不确定如何继续。

我们遇到了类似的问题。我们觉得我们需要建立一个逻辑,使HTTP 处理响应的逻辑可访问的调用。他们在街上是分开的 代码,所以服务是一种很好的方法

我们通过将
$http.get
调用包装到一个 缓存响应,并在缓存不可用时立即调用成功回调 已经有人了。例如

app.service('authorizationService', ['authority', function (authority) {
    var requestData = undefined;

    return {
        get: function (successCallback) {
            if (typeof requestData !== 'undefined') {
                successCallback(requestData);
            }
            else {
                $http.get('/svc/account/identity').success(function (data) {
                    requestData = data;
                    successCallback(data);
                });
            }
        }
    };
}]);
这在请求成功时起到了保护作用。然后,您可以在
$stateChangeStart
安全处理

当调用
authorizationService.get()
时,如果请求已经在进行中,这种方法容易受到竞争条件的影响。有可能引入一些XHR簿记来防止这种情况

或者,您可以在HTTP请求完成后发布自定义事件 已完成,并在
$stateChangeStart
处理程序。以后需要注销该处理程序 但是,可能在
$stateChangeEnd
处理程序中

在授权完成之前,所有这些都无法完成,因此您应该通知 通过显示加载视图,用户知道他们需要等待

此外,在中还对使用
ui路由器进行身份验证进行了一些有趣的讨论

在AngularJS谷歌群上。

好吧,在做了大量的头发拉扯之后,以下是我的发现

  • 正如您所料,
    resolve
    是启动任何异步调用并确保在状态转换为之前完成调用的适当位置
  • 您需要为所有状态创建一个抽象父状态,以确保您的
    解析发生,这样,如果有人刷新浏览器,您的异步解析仍会发生,并且您的身份验证工作正常。您可以使用
    状态
    上的
    parent
    属性创建另一个状态,否则该状态将不会通过命名/点表示法继承。这有助于防止州名称变得无法管理
  • 虽然您可以将所需的任何服务注入到您的
    resolve
    ,但您无法访问它试图转换到的状态的
    toState
    toStateParams
    。但是,
    $stateChangeStart
    事件将在您的
    解决之前发生。因此,您可以将
    toState
    toStateParams
    从事件参数复制到
    $rootScope
    ,并将
    $rootScope
    注入到
    resolve
    函数中。现在您可以访问它试图转换到的状态和参数
  • 解析资源后,您可以使用承诺进行授权检查,如果授权检查失败,请使用
    $state.go()
    将其发送到登录页面,或者执行任何需要执行的操作。当然,这有一个警告
  • 一旦在父状态下完成了
    resolve
    ,ui路由器将不会再次解析它。这意味着你的安全检查不会发生!啊!解决这个问题的办法是进行两部分检查。一旦进入
    解决
    ,我们已经讨论过了。第二次是在
    $stateChangeStart
    事件中。这里的关键是检查资源是否已解决。如果是,请执行与您在
    resolve
    中执行的相同的安全检查,但在事件中。如果资源解析,则签入
    resolve
    将拾取该资源。要实现这一点,您需要管理服务中的资源,以便能够适当地管理状态
  • 其他一些杂项。注:

    • 不要费心把所有的authz逻辑塞进
      $stateChangeStart
      。虽然您可以阻止该事件并执行异步解析(在准备就绪之前有效地停止更改),然后尝试在promise成功处理程序中恢复状态更改,但仍有一些问题妨碍了该处理程序的正常工作
    • 无法在当前状态的
      oneter
      方法中更改状态

    是一个很好的例子。

    我认为处理这种情况的更干净的方法是t
    $urlRouterProvider。延迟拦截()
    $urlRouter.listen()
    一起停止uiRouter,直到从服务器检索到某些数据


    有关更多信息,请参阅和。

    是的,我认为使用我的身份验证服务中的
    $q
    的每个州的
    解析
    听起来最有希望。我来试一试。你能详细说明一下你的第一个杂项吗。请注意,以“不要费心去死记硬背…”开头。具体的