【问题标题】:$stateChangeStart run before getting data from Rest API$stateChangeStart 在从 Rest API 获取数据之前运行
【发布时间】:2016-05-06 18:49:35
【问题描述】:

我尝试进行用户登录身份验证,我使用 isAuthenticated 方法创建了一个名为 AuthService 的服务,在该服务中我调用 API 以交叉检查用户是否登录(另外我' 稍后将在其中使用用户角色),然后我在 $rootScope.$on 中调用此服务,但它不会等到我的服务从 API 获取数据,这是我的 app.js

var app = angular.module('myApp', ['ngRoute', 'ui.router', 'ngAnimate', 'toaster', 'ui.bootstrap']);

app.config(['$routeProvider', '$locationProvider', '$stateProvider', '$urlRouterProvider',
  function ($routeProvider, $locationProvider, $stateProvider, $urlRouterProvider) {
        $stateProvider.
        state('/', {
            url: "/",
            views: {
                header: {
                    templateUrl: 'partials/common/header.html',
                    controller: 'authCtrl',
                },
                content: {
                    templateUrl: 'partials/dashboard.html',
                    controller: 'authCtrl',
                }
            },
            title: 'Dashboard',
            authenticate: true
        })

        .state('login', {
            url: "/login",
            views: {
                content: {
                    templateUrl: 'partials/login.html',
                    controller: 'authCtrl',
                }
            },
            title: 'Login',
            authenticate: false
        })        

        .state('dashboard', {
            title: 'Dashboard',
            url: "/dashboard",
            views: {
                header: {
                    templateUrl: 'partials/common/header.html',
                    controller: 'authCtrl',
                },
                content: {
                    templateUrl: 'partials/dashboard.html',
                    controller: 'authCtrl',
                }
            },
            authenticate: true
        });
        $urlRouterProvider.otherwise("/");

        //check browser support
        if(window.history && window.history.pushState){
            $locationProvider.html5Mode({
                 enabled: true,
                 requireBase: false
            });
        }
  }])
 .run(function ($rootScope, $location, $state, Data, AuthService) {
        $rootScope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams) {
            $rootScope.title = toState.title;
            $rootScope.authenticated = false;
            var userInfo = AuthService.isAuthenticated();
            if (toState.authenticate && !AuthService.isAuthenticated()){
                  // User isn’t authenticated
                  $state.transitionTo("login");
                  event.preventDefault();
            } else {
               alert('here I am ='+$rootScope.authenticated);
            }
        });
    });

这是我的服务

app.factory('AuthService', function ($http, Data, $rootScope) {
  var authService = {};

  authService.isAuthenticated = function () {
    Data.get('index.php/api/authentication/is_login').then(function (results) {
        if (results.uid) {
            $rootScope.authenticated = true;
            $rootScope.uid = results.uid;
            $rootScope.name = results.name;
            $rootScope.email = results.email;
            return results.uid;
        } else {
            return false;
        }
    });
  }
  return authService;
});

尝试了很多东西,但到目前为止没有运气,请提出一个最好的方法,我已经尝试了 ui-routes 中的 resolve 方法,但没有奏效。

提前致谢。

【问题讨论】:

  • 你为什么用php标记这个问题?
  • 因为我正在使用 codeigniter for rest API

标签: php angularjs authentication angular-ui-router


【解决方案1】:

您当前的实现将无法工作,因为Data.get() 函数返回Promise,因此是异步的。因此,路由更改将继续进行,而无需等到您的身份验证服务返回任何值。

要解决您的问题,您应该以特定方式处理此异步逻辑:

app.run(function ($rootScope, $location, $state, Data, AuthService) {
  $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
    /**
     * If the user is heading towards a state that requires
     * authentication, assume that they are not authenticated,
     * and stop them! Otherwise, let them through...
     */
    if (toState.authenticate) {
      event.preventDefault();

      if (toState.name !== fromState.name) {
        // Now check whether or not they are authenticated
        AuthService.isAuthenticated().then(function () {
          // Yes! They're authenticated, continue
          $state.go(toState.name, toParams);
        }, function () {
          // Nope, this user cannot view this page
          alert('You cannot view this page!');
        });
      }
    } else {
      return;
    }
  });
}

编辑:我添加了一个检查语句toState.name !== fromState.name 以中断任何可能导致对身份验证服务的无休止调用的重定向循环。这是对问题原始发布者的评论的回应。

诀窍是防止路由转换,默认情况下。然后,您可以在允许用户继续前进之前尽可能多地执行异步逻辑。

我建议添加一个微调器或加载窗口,以提醒用户您正在执行此身份验证检查。阻止用户在页面上进行任何进一步的操作也可能是明智之举,但这完全取决于您。

请注意,函数AuthService.isAuthenticated() 现在返回一个Promise,您必须对您的身份验证服务稍作更改才能实现此目的。像这样简单地包装你当前的逻辑:

app.factory('AuthService', function ($http, Data, $rootScope, $q) {
  var authService = {};

  authService.isAuthenticated = function () {
    return $q(function (resolve, reject) {
      Data.get('index.php/api/authentication/is_login').then(function (results) {
        if (results.uid) {
          $rootScope.authenticated = true;
          $rootScope.uid = results.uid;
          $rootScope.name = results.name;
          $rootScope.email = results.email;

          // Great, the user is authenticated, resolve the Promise
          resolve(results.uid);
        } else {
          // The user does not appear to be authenticated, reject the Promise
          reject();
        }
      });
    });
  };

  return authService;
});

我希望这可以解决您的问题,Promises 可能会很痛苦,但它们也可以是一个非常强大的工具。 GitHub 上有一个很好的帖子讨论了围绕这个问题的一些潜在解决方案,可以在这里找到:https://github.com/angular-ui/ui-router/issues/1399


【讨论】:

  • 非常感谢您的回复。我已经实现它并在我的控制台中出现错误 TypeError: Cannot read property 'then' of undefined
  • 您是否更新了您的AuthService.isAuthenticated(),使其返回Promise
  • 是的,我更改了我的服务,现在我的 http 请求在用户登录时返回用户数据,如果用户未登录,则返回一个空白对象
  • 我已经修复了错误“无法读取未定义的属性 'then'”,但是当 http 请求对任何用户进行身份验证时,它会重定向到 $state.go(toState.name, toParams);,它进入无限循环调用http请求来验证用户。
  • 您可以在调用AuthService.isAuthenticated()之前添加一个检查以确认该状态与上一个状态肯定不同,我会更新帖子。
猜你喜欢
  • 2021-04-24
  • 2019-04-28
  • 2018-02-19
  • 1970-01-01
  • 2017-05-26
  • 2015-07-05
  • 2018-03-11
  • 2015-12-04
  • 1970-01-01
相关资源
最近更新 更多