【问题标题】:Angular JS - Preventing a controller from runningAngular JS - 防止控制器运行
【发布时间】:2014-04-11 04:03:15
【问题描述】:

所以我正在做一个简单的“用户是否登录”检查并在用户未登录时将其重定向到 signin.html 页面。我的代码如下所示:

var myAppModule = angular.module('myApp', ['ngRoute', 'ngCookies']);

myAppModule.config(function($routeProvider) {
$routeProvider
.when('/page2', {
    controller:'pagetwo',
    templateUrl:'pagetwo.html'
})
.when('/signin', {
    controller:'signinCTRL',
    templateUrl:'signin.html'
})

});

myAppModule.run(function($rootScope, userInfo, $location) {
$rootScope.$on('$routeChangeSuccess', function () {
    myCurrentRoute = $location.$$path;

    if(myCurrentRoute != "/signin") {
        userInfo.checkLogin(); //  Check login first. This has the $location.path( "/signin" ); in it.
    }
})

});

我的问题是,当用户转到 /page2 时,$routeChangeSuccess 函数会正常触发,并且在 userInfo.checkLogin() 内部我将它们重定向到将它们重定向到 signin.html 页面上的新路由。

问题是 pagetwo 控制器在用户被重定向到 signinCTRL 控制器之前仍然触发

有没有办法阻止 pagetwo 控制器以某种方式运行? 我知道我可能只是将所有内容包装在 signinCTRL 中以检查用户是否已登录,但这违背了拥有routeChangeSuccess 函数。

【问题讨论】:

  • 很好奇你为什么要做这个客户端。如果用户导航到他们无权查看的页面,您应该让服务器返回 403 错误。然后你可以抓住它并重定向到登录页面。
  • @BenFelda - 真的,所有真正的用户身份验证都通过 PHP 在服务器端发生。没有经过授权的 php 会话,JS 不可能调用 pages/files/data。我只关心抛出不需要发生的错误。这个特殊的项目也是我使用 Angular 的一次学习经历。

标签: angularjs angularjs-routing angularjs-controller


【解决方案1】:

您可以关注$locationChangeStart 事件,而不是关注$routeChangeSuccess

$locationChangeStart 在控制器被调用之前被触发。

您可以在how to cancel route navigation in angular 上的此博客中阅读有关$locationChangeStart$routeChangeStart 之间区别的更多信息

demo plunker 使用 $locationChangeStart

【讨论】:

  • 这正是我想要的。谢谢。
【解决方案2】:

我已经处理了登录功能由我的 Angular js 应用程序之外的 servlet 处理的这个问题。

我通过 javax.servlet.Filter 控制对应用程序的访问

我还有另一个过滤器,用于处理来自应用程序的所有 Json 请求。

对于未经身份验证的用户场景,Json 过滤器的行为如下;

 httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); //401

我添加了一个 $rootScope 方法,该方法强制登录来自 JSON 控制器的任何 401 响应。

   $rootScope.handleHttpFailure = function(data,status) {
        if (401 == status) {
            document.location.reload(true);
        }  else {
            console.log("post ERROR status:" + status + " response:" + data);
            $rootScope.alert('Error received status:'+ status + " response:" + data );
        }
    }

因此,对于您的场景,您无法阻止 pagetwo 控制器运行,但如果您遵循这个相当简单的模式,则可以阻止它访问受保护的资源。

【讨论】:

    【解决方案3】:

    收听$routeChangeStart 而不是$routeChangeSuccess 事件可能会在短期内解决您的问题。您还可以在路由resolve 映射承诺之一中进行登录检查,然后只返回一个因登录失败而关闭的承诺。然后收听 $routeChangeError 可以导航到 signin url,或者只是从解析承诺导航到它。

    对于更完整和更强大的路由解决方案,您可能应该使用ui-router,路由器任何严重的 Angular 应用程序都应该使用(并且传闻将来会进入 Angular 核心)。

    是的,您应该在服务器端验证正确的登录和授权,并返回 401 响应以防它无效(然后您可以使用美妙的http auth interceptor 来处理错误。但我不同意考虑到您应该在服务器端进行,这很容易导致糟糕的用户体验,您当然应该在客户端进行基本测试

    【讨论】:

      【解决方案4】:

      这是处理错误的最佳方法,并且效果很好

      function ($routeProvider, $locationProvider, $httpProvider) {
          var interceptor = [
              '$rootScope', '$q', function (scope, $q) {
      
                  function success(response) {
                      return response;
                  }
      
                  function error(response) {
                      var status = response.status;
      
                      if (status == 401) {
                          var deferred = $q.defer();
                          var req = {
                              config: response.config,
                              deferred: deferred
                          };
                          window.location = "/";
                      }
      
                      if (status == 404) {
                          var deferred = $q.defer();
                          var req = {
                              config: response.config,
                              deferred: deferred
                          };
                          window.location = "#/404";
                      }
                      // otherwise
                      //return $q.reject(response);
                      window.location = "#/500";
                  }
      
                  return function (promise) {
                      return promise.then(success, error);
                  };
      
              }
          ];
          $httpProvider.responseInterceptors.push(interceptor);
      });
      
      // routes
      app.config(function($routeProvider, $locationProvider) {
          $routeProvider
              .when('/404', {
                  templateUrl: '/app/html/inserts/error404.html',
                  controller: 'RouteCtrl'
              })
              .when('/500', {
                  templateUrl: '/app/html/inserts/error404.html',
                  controller: 'RouteCtrl'
              })
      
              ......
      
         };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-21
        • 2019-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多