Angular.js:页面在身份验证重定向上闪烁

时间:2015-04-01 02:21:23

标签: angularjs authentication angular-ui-router

我在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

1 个答案:

答案 0 :(得分:2)

您目前的工作方式是检查用户是否已登录,并将load设置为truefalse。在load被解析之前,控制器也会被实例化,这就是你看到闪烁的原因。你需要在这里完成两件事:

  1. 确保在实例化控制器之前解析load
  2. 如果用户未登录,请将用户重定向到登录页面。
  3. 对于第一部分,我们需要使用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重定向用户。