如何使用 $routeProvider 限制路由

How to restrict routes with $routeProvider

在 MEAN 应用程序中,我有一个带有 Auth 工厂的 authService 模块,其中包含一个 authFactory.isLoggedIn 函数:

// check if a user is logged in
    // checks if there is a local token
    authFactory.isLoggedIn = function() {
        if (AuthToken.getToken()) 
            return true;
        else
            return false;   
    };

所以我想我可以像这样将它与 $routeProvider 的解析 属性 一起使用:

var MyModule = angular.module('app.routes', ['ngRoute']);

MyModule.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {


    $routeProvider

        // route for the home page
        .when('/', {
            templateUrl : 'app/views/pages/home.html'
        })

        // login page
        .when('/login', {
            templateUrl : 'app/views/pages/login.html',
            controller  : 'mainController',
                controllerAs: 'login'
        })

        // register page
        .when('/register', {
            templateUrl: 'app/views/pages/register.html',
            controller: 'userCreateController',
            controllerAs: 'register'
        })

        // upload page
        .when('/upload', {
            templateUrl : 'app/views/pages/upload.html',
            controller: 'uploadController',
            controllerAs: 'userupload',
            resolve: function($q, $location) {
                var deferred = $q.defer();
                deferred.resolve();
                if (!Auth.isLoggedIn) {
                    $location.path('/login');
                }
                return deferred.promise;
            }

        })

        //logout
        .otherwise({redirectTo: '/'});

    $locationProvider.html5Mode(true);

}]);

遗憾的是,这无法阻止未经身份验证的用户访问上传页面,而且我没有看到任何错误报告。 我见过一些更简单的方法来做到这一点,例如:

.when('/upload', {
            templateUrl : 'app/views/pages/upload.html',
            controller: 'uploadController',
            controllerAs: 'userupload',
            isLoggedIn: true

        })

但这也行不通,这很遗憾,因为它要简单得多。

添加自定义 http 拦截器。这不是精确的代码,只是算法,可能缺少一些语法:

.factory('myHttpInterceptor', function($q, $location, AuthToken) {

    function isLoggedIn() {
        return !!AuthToken.getToken();
    }

    function canRecover(response) {
        var status = response.status;
        var config = response.config;
        var method = config.method;
        var url = config.url;

        console.log("--->>> ", method, status, url);

        if (status == 401) {
            alert("401");
        } else if ( status == 403) {
            alert("403");
        } else if (status == 404) {
            alert("404");
        } else if (status == 405) {
            alert("405");
        } else if (status == 500) {
            alert("500");
        } else {
        }
        return response;
    }

    return {
        // optional method
        'request': function(config) {
            if (isLoggedIn()) {
                return config;
            } else {
                $location.path('login');
            }
        },

        // optional method
        'response': function(response) {
        // do something on success
        return response;
        },

        // optional method
        'requestError': function(rejection) {
            return $q.reject(canRecover(rejection));
        },

        // optional method
        'responseError': function(rejection) {
            return $q.reject(canRecover(rejection));
        }
    };
})
.config(['$httpProvider', function($httpProvider) {
    $httpProvider.interceptors.push('myHttpInterceptor');
}])

您可以通过多种方式实现此功能。

最简单的方法是向您不希望用户访问的每个控制器添加类似于以下代码的检查。

// You could re-direct the user to a '401' state as well
if (!authFactory.isLoggedIn())
  $state.go('login');

最后我决定使用$routeProvider 的解析属性 所以在http://midgetontoes.com/blog/2014/08/31/angularjs-check-user-login 上尝试了解决方案之后 我想到了:

var MyModule = angular.module('app.routes', ['ngRoute']);

MyModule.config(['$routeProvider', '$locationProvider', function($routeProvider, $locationProvider) {

    var onlyLoggedIn = function($location, $q, Auth) {
        var deferred = $q.defer();
        if (Auth.isLoggedIn()) {
            deferred.resolve();
        } else {
            deferred.reject();
            $location.url('/login');
        }
        return deferred.promise;
    };


    $routeProvider

        // route for the home page
        .when('/', {
            templateUrl : 'app/views/pages/home.html'
        })

        // login page
        .when('/login', {
            templateUrl : 'app/views/pages/login.html',
            controller  : 'mainController',
                controllerAs: 'login'
        })

        // register page
        .when('/register', {
            templateUrl: 'app/views/pages/register.html',
            controller: 'userCreateController',
            controllerAs: 'register'
        })

        // upload page
        .when('/upload', {
            templateUrl : 'app/views/pages/upload.html',
            controller: 'uploadController',
            controllerAs: 'userupload',
            resolve:{loggedIn:onlyLoggedIn}


        })

        //logout
        .otherwise({redirectTo: '/'});

    $locationProvider.html5Mode(true);

}]);

我确信这不如@Dimitiri Algazin 提出的自定义 http 拦截器好,也不如@Pasan Ratnayake 的解决方案简单,但它确实满足了我使用 resolve 的要求。无论如何都要感谢@Dimitri 和@Pasan。