php - $stateChangeStart 在从 Rest API 获取数据之前运行

标签 php angularjs authentication angular-ui-router

我尝试进行用户登录身份验证,我创建了一个名为 AuthService 的服务,方法是 isAuthenticated,我在其中调用 API 进行交叉检查用户是否登录(稍后我将在其中使用用户 Angular 色),然后我在 $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 方法,但没有奏效。

提前致谢。

最佳答案

您当前的实现将不起作用,因为 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;
    }
  });
}

Edit: I have added a check statement toState.name !== fromState.name to break any redirect loops that may then cause endless calls to the authentication service. This was in response to a comment made by the original poster of the issue.

The trick is to prevent the route transition, by default. You are then able to perform as much asynchronous logic as you wish before the user is permitted to move any further on.

I would recommend adding a spinner, or a loading window, to alert the user to the fact that you are performing this authentication check. It may also be wise to prevent any further user actions on the page, but that's entirely up to you.

请注意,函数 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 .


关于php - $stateChangeStart 在从 Rest API 获取数据之前运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37045474/

相关文章:

javascript - jquery metismenu 无法与 AngularJS Controller 异步加载数据

android - Android 中的共享首选项?

javascript - 如何使用 node.js 抓取需要身份验证的网站?

php - Laravel 4 中的多种用户类型 - 登录问题

javascript - 在 cordova/ratchet 移动应用程序中发出 AJAX 请求时遇到困难

php - 摆脱 mysql_real_escape_string() 解析字符串上的\字符

javascript - 自定义指令内 ngDirectives 的奇怪行为

javascript - 单击 Protractor 中的表格单元格值

php - 在哪里存储上传的文件(声音、图片和视频)

php - 在 Core Php 和 CodeIgniter 之间共享 session