即使重定向,ui-router StateChange事件也会通过

时间:2015-04-14 00:24:39

标签: angularjs angular-ui-router

我正在使用AngularJS和ui-router开发OAuth提供程序应用程序。 对于每个州的变更,我都会进行以下检查:

  1. 如果用户已登录: 1.1如果用户不是管理员 - >将他重定向到callBackUrl 1.2如果用户是管理员,则不执行任何操作

  2. 如果用户未登录: 2.1如果用户尝试访问管理页面 - >将他重定向回登录 2.2如果没有,什么都不做

  3. 我的ui-router运行方法如下:

    .run(function ($rootScope, $state, $auth, accountService, $window, $stateParams) {
        $rootScope.$on('$stateChangeStart', function (e, toState, toParams, fromState, fromParams) {
            accountService.getUser({ token: $auth.getToken() }).$promise
                .then(function (response) {
                    if (response.isAdmin === false) {
                        e.preventDefault();
                        $window.location.href = $stateParams.callBackUrl;
                        return;
                    }
                })
                .catch(function (response) {
                    if (toState.name.split(".")[0] === 'admin') {
                        e.preventDefault();
                        $state.go('root.login');
                    }
                });
        });
    });
    

    除了使用$ window

    将用户重定向到回调网址的部分外,一切正常
    $window.location.href = $stateParams.callBackUrl;
    

    此重定向需要2-3秒,与此同时,我的用户可以看到他尝试在我的应用程序上访问的页面。我认为使用preventDefault()可以解决这个问题,但事实并非如此。你知道如何保存$ statechangeevent以便用户直接重定向到回调URL吗?

    由于

2 个答案:

答案 0 :(得分:2)

我会这样说:

  

上述方法允许用户使用所有内容,直到他没有真正证明是经过联合国身份验证的。为什么?因为代码正在调用服务,并且在收到数据后评估所有内容。同时 - 我们信任用户。

所以,我建议改变方法

  

永远不要信任用户。他/她必须尽最大努力证明他/她是正确的,才能到达某个地方...... (好吧,那种......)

我在这里描述了一种可能的方式(带有工作示例)

Confusing $locationChangeSuccess and $stateChangeStart

只需要一段代码来引用

$rootScope.$on('$stateChangeStart', ...的第一部分:

    // if already authenticated...
    var isAuthenticated = userService.isAuthenticated();
    // any public action is allowed
    var isPublicAction = angular.isObject(toState.data)
                       && toState.data.isPublic === true;    


    // here - user has already proved that he is the one
    // or the target is public (e.g. login page)
    // let him go, get out of this check

    if (isPublicAction || isAuthenticated) {
      return;
    }

第二部分,用户不受信任,他需要访问私人内容

    // now - stop everything
    // NO navigation
    // we have to be sure who user is, to continue

    // stop state change
    event.preventDefault();

    // async load user 
    userService
       .getAuthObject()
       .then(function (user) {

          var isAuthenticated = user.isAuthenticated === true;

          if (isAuthenticated) {
            // let's continue, use is allowed
            $state.go(toState, toParams)
            return;
          }    
          // log on / sign in...
          $state.go("login");
       })

在行动中检查here

答案 1 :(得分:0)

我知道这是前一段时间被问过的,但这是一个可能的解决方案:

Ui-router实际上提供了解决此问题的绝佳方法。通过使用"解决"在$ stateProvider中,您可以检查用户是否在特定状态的控制器被实例化之前进行了身份验证。以下是ui-router docs关于解决方案的说法:

  

<强>解析

     

您可以使用resolve为您的控制器提供自定义状态的内容或数据。 resolve是一个可选的依赖关系图,应该注入控制器。

     

如果这些依赖项中的任何一个是promise,它们将被解析并转换为值,然后实例化控制器并触发$ stateChangeSuccess事件。

https://github.com/angular-ui/ui-router/wiki - resolve的部分几乎是页面的一半

您可以在解决方案中运行accountService.getUser以检查经过身份验证的用户,这样做可以防止未通过身份操作的人看到他们尝试路由到的视图。

在$ stateProvider中设置了解析,可能看起来像这样:

$stateProvider.state('myState', {
  resolve: {
    userAuth: function(accountService) {
      return accountService.getUser();
    }
  }
)

如果您在上面的示例中注意到,我在解析中设置了一个名为userAuth的属性。现在可以将其注入任何控制器或服务,然后您可以针对经过身份验证的用户进行检查。需要成为受保护的每个州的#34;视图可以包含解析,然后视图的2-3秒闪烁不会发生,因为控制器尚未实例化,并且用户被重定向到另一个状态。