我正在写一个小的AngularJS应用程序,它有一个登录视图和一个主视图,配置如下:

$routeProvider
 .when('/main' , {templateUrl: 'partials/main.html',  controller: MainController})
 .when('/login', {templateUrl: 'partials/login.html', controller: LoginController})
 .otherwise({redirectTo: '/login'});

我的LoginController检查user/pass组合,并在$rootScope上设置一个属性:

function LoginController($scope, $location, $rootScope) {
 $scope.attemptLogin = function() {
   if ( $scope.username == $scope.password ) { // test
        $rootScope.loggedUser = $scope.username;
        $location.path( "/main" );
    } else {
        $scope.loginError = "Invalid user/pass.";
    }
}

一切正常,但如果我访问http://localhost/#/main,我最终绕过了登录屏幕。我想写一些类似于“每当路由改变,如果$rootScope。loggedUser为空,然后重定向到/login"

...

... 等待。我能以某种方式听到路线变化吗?不管怎样,我会把这个问题发布出来,继续寻找。


当前回答

使用angular-ui-router可以重定向到另一个视图。为此,我们使用了$state.go("target_view")方法。例如:

 ---- app.js -----

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

 app.config(function ($stateProvider, $urlRouterProvider) {

    // Otherwise
    $urlRouterProvider.otherwise("/");

    $stateProvider
            // Index will decide if redirects to Login or Dashboard view
            .state("index", {
                 url: ""
                 controller: 'index_controller'
              })
            .state('dashboard', {
                url: "/dashboard",
                controller: 'dashboard_controller',
                templateUrl: "views/dashboard.html"
              })
            .state('login', {
                url: "/login",
                controller: 'login_controller',
                templateUrl: "views/login.html"
              });
 });

 // Associate the $state variable with $rootScope in order to use it with any controller
 app.run(function ($rootScope, $state, $stateParams) {
        $rootScope.$state = $state;
        $rootScope.$stateParams = $stateParams;
    });

 app.controller('index_controller', function ($scope, $log) {

    /* Check if the user is logged prior to use the next code */

    if (!isLoggedUser) {
        $log.log("user not logged, redirecting to Login view");
        // Redirect to Login view 
        $scope.$state.go("login");
    } else {
        // Redirect to dashboard view 
        $scope.$state.go("dashboard");
    }

 });

----- HTML -----

<!DOCTYPE html>
<html>
    <head>
        <title>My WebSite</title>

        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <meta name="description" content="MyContent">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <script src="js/libs/angular.min.js" type="text/javascript"></script>
        <script src="js/libs/angular-ui-router.min.js" type="text/javascript"></script>
        <script src="js/app.js" type="text/javascript"></script>

    </head>
    <body ng-app="myApp">
        <div ui-view></div>
    </body>
</html>

其他回答

以下是我的做法,希望对大家有所帮助:

在配置中,我在我想向公众开放的少数路由上设置了一个publicAccess属性(比如登录或注册):

$routeProvider
    .when('/', {
        templateUrl: 'views/home.html',
        controller: 'HomeCtrl'
    })
    .when('/login', {
        templateUrl: 'views/login.html',
        controller: 'LoginCtrl',
        publicAccess: true
    })

然后在一个运行块中,我在$routeChangeStart事件上设置了一个监听器,它重定向到'/login',除非用户有访问权限或路由是公共可访问的:

angular.module('myModule').run(function($rootScope, $location, user, $route) {

    var routesOpenToPublic = [];
    angular.forEach($route.routes, function(route, path) {
        // push route onto routesOpenToPublic if it has a truthy publicAccess value
        route.publicAccess && (routesOpenToPublic.push(path));
    });

    $rootScope.$on('$routeChangeStart', function(event, nextLoc, currentLoc) {
        var closedToPublic = (-1 === routesOpenToPublic.indexOf($location.path()));
        if(closedToPublic && !user.isLoggedIn()) {
            $location.path('/login');
        }
    });
})

显然,你可以将条件从isLoggedIn更改为其他任何条件…只是展示了另一种方法。

在深入研究了一些文档和源代码之后,我想我已经让它工作了。也许这对其他人有用?

我在我的模块配置中添加了以下内容:

angular.module(...)
 .config( ['$routeProvider', function($routeProvider) {...}] )
 .run( function($rootScope, $location) {

    // register listener to watch route changes
    $rootScope.$on( "$routeChangeStart", function(event, next, current) {
      if ( $rootScope.loggedUser == null ) {
        // no logged user, we should be going to #login
        if ( next.templateUrl != "partials/login.html" ) {
          // not going to #login, we should redirect now
          $location.path( "/login" );
        }
      }         
    });
 })

有一件事似乎很奇怪,我必须测试部分名称(login.html),因为“next”Route对象没有url或其他东西。也许有更好的办法?

这里可能有一个更优雅、更灵活的解决方案,它具有“resolve”配置属性和“promises”,可以根据数据在路由和路由规则上最终加载数据。

你在路由配置中的“resolve”和函数加载和检查数据中指定一个函数,做所有重定向。如果你需要加载数据,你返回一个承诺,如果你需要重定向-拒绝承诺之前。 所有细节都可以在$routerProvider和$q文档页找到。

'use strict';

var app = angular.module('app', [])
    .config(['$routeProvider', function($routeProvider) {
        $routeProvider
            .when('/', {
                templateUrl: "login.html",
                controller: LoginController
            })
            .when('/private', {
                templateUrl: "private.html",
                controller: PrivateController,
                resolve: {
                    factory: checkRouting
                }
            })
            .when('/private/anotherpage', {
                templateUrl:"another-private.html",
                controller: AnotherPriveController,
                resolve: {
                    factory: checkRouting
                }
            })
            .otherwise({ redirectTo: '/' });
    }]);

var checkRouting= function ($q, $rootScope, $location) {
    if ($rootScope.userProfile) {
        return true;
    } else {
        var deferred = $q.defer();
        $http.post("/loadUserProfile", { userToken: "blah" })
            .success(function (response) {
                $rootScope.userProfile = response.userProfile;
                deferred.resolve(true);
            })
            .error(function () {
                deferred.reject();
                $location.path("/");
             });
        return deferred.promise;
    }
};

说俄语的人habr上有一篇文章“ВариантусловногораутингавAngularJS。”

在你的app.js文件中:

.run(["$rootScope", "$state", function($rootScope, $state) {

      $rootScope.$on('$locationChangeStart', function(event, next, current) {
        if (!$rootScope.loggedUser == null) {
          $state.go('home');
        }    
      });
}])

实现登录重定向的另一种方法是使用这里描述的事件和拦截器。本文描述了一些额外的优点,例如检测何时需要登录、排队请求以及在登录成功后重新播放它们。

您可以在这里尝试一个工作演示,并在这里查看演示源代码。