Redireccionar a una ruta determinada según la condición

493

Estoy escribiendo una pequeña aplicación AngularJS que tiene una vista de inicio de sesión y una vista principal, configurada así:

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

Mi LoginController comprueba la combinación usuario / pase y establece una propiedad en $ rootScope que refleja esto:

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.";
    }
}

Todo funciona, pero si http://localhost/#/mainaccedo termino saltando la pantalla de inicio de sesión. Quería escribir algo como "cada vez que cambie la ruta, si $ rootScope.loggedUser es nulo, redirigir a / login"

...

... Espere. ¿Puedo escuchar los cambios de ruta de alguna manera? Publicaré esta pregunta de todos modos y seguiré buscando.

st.never
fuente
3
Solo para aclarar: si bien muchas de las soluciones a continuación funcionan bien, recientemente he estado más inclinado a aceptar la respuesta de @ Oran a continuación, es decir, hacer que el servidor responda con un código 401 cuando se le solicite una URL sensible y use esa información para controlar el "cuadro de inicio de sesión" en el cliente. (Sin embargo, el jurado todavía está en el bit de "
poner en

Respuestas:

510

Después de sumergirme un poco en la documentación y el código fuente, creo que lo hice funcionar. ¿Quizás esto sea útil para alguien más?

Agregué lo siguiente a la configuración de mi módulo:

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" );
        }
      }         
    });
 })

Lo único que parece extraño es que tuve que probar el nombre parcial (login.html ) porque el "siguiente" objeto de ruta no tenía una URL o algo más. Tal vez hay una mejor manera?

st.never
fuente
13
Genial, gracias por compartir tu solución. Una cosa a tener en cuenta: en la versión actual, es "siguiente. $ Route.templateUrl"
doubledriscoll
55
Si observa las solicitudes de red en chrome inspector, la ruta que se está redirigiendo (porque el usuario no ha iniciado sesión) aún se llama y se envía una respuesta al navegador, y luego se llama a la ruta redirigida '/ inicio de sesión'. Por lo tanto, este método no es bueno ya que los usuarios que no han iniciado sesión pueden ver la respuesta para una ruta a la que no deberían tener acceso.
sonicboom
34
Use $ locationChangeStart en lugar de $ routeChangeStart para evitar que se llame a la ruta y permitir que los usuarios no autenticados vean contenido al que no deberían tener acceso.
sonicboom
17
Recuerda que este es el cliente. También debería haber una barrera en el servidor.
Neikos
2
@sonicboom $ locationChangeStart no tiene sentido si no todas las rutas requieren autenticación, con $ routeChangeStart puede tener metadatos en los objetos de la ruta, como si está autenticado o no o qué roles se requieren para esa ruta. Su servidor debe manejar no mostrar contenido no autenticado y AngularJS no comenzará a procesar hasta después de que la ruta cambie de todos modos, por lo que no se debe mostrar nada.
Chris Nicola
93

Esta es quizás una solución más elegante y flexible con la propiedad de configuración 'resolver' y las 'promesas' que permiten la carga de datos eventuales en el enrutamiento y las reglas de enrutamiento dependiendo de los datos.

Usted especifica una función en 'resolver' en la configuración de enrutamiento y en la función cargar y verificar datos, hacer todos los redireccionamientos. Si necesita cargar datos, devuelve una promesa, si necesita redirigir, rechace la promesa antes de eso. Todos los detalles se pueden encontrar en las páginas de documentación $ routerProvider y $ 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;
    }
};

Para las personas de habla rusa hay una publicación en habr " Вариант условного раутинга в AngularJS ".

Nikolay Popov
fuente
1
¿Por qué se asigna la función checkRouting a la fábrica? ¿Importa a qué está asignado?
honkskillet
@honkskillet: De los documentos angulares $ routeProvider: "factory - {string | function}: Si es string, entonces es un alias para un servicio. De lo contrario, si es función, se inyecta y el valor de retorno se trata como la dependencia. Si el el resultado es una promesa, se resuelve antes de que su valor se inyecte en el controlador. Tenga en cuenta que ngRoute. $ routeParams todavía se referirá a la ruta anterior dentro de estas funciones de resolución. Use $ route.current.params para acceder a los nuevos parámetros de ruta, en lugar." También de los documentos sobre la resolución: "Si se rechaza alguna de las promesas, se activa el evento $ routeChangeError".
Tim Perry
Si ui.routerse usa, use en $stateProvider lugar de $routeProvider.
TRiNE
61

He estado tratando de hacer lo mismo. Se le ocurrió otra solución más simple después de trabajar con un colega. Tengo un reloj configurado $location.path(). Eso hace el truco. Estoy empezando a aprender AngularJS y encuentro que esto es más limpio y legible.

$scope.$watch(function() { return $location.path(); }, function(newValue, oldValue){  
    if ($scope.loggedIn == false && newValue != '/login'){  
            $location.path('/login');  
    }  
});
usuario1807337
fuente
Esto se ve muy interesante. ¿Pudiste publicar un ejemplo en alguna parte?
kyleroche
3
¿Dónde configuras el reloj?
freakTheMighty
3
@freakTheMighty Debe configurar el reloj en su función mainCtrl, donde ng-controller está configurado en mainCtrl. por ejemplo, <body ng-controller = "mainCtrl">
user1807337
55
Creo que es justo que si se da un voto negativo, debería haber un comentario con razón. Ayudará como una herramienta de aprendizaje.
user1807337
37

Una forma diferente de implementar la redirección de inicio de sesión es usar eventos e interceptores como se describe aquí . El artículo describe algunas ventajas adicionales, como detectar cuándo se requiere un inicio de sesión, poner en cola las solicitudes y volver a reproducirlas una vez que el inicio de sesión es exitoso.

Puede probar una demostración funcional aquí y ver la fuente de demostración aquí .

Oran Dennison
fuente
3
¿Podría actualizar esta respuesta para incluir la información relevante de los enlaces? De esa manera, seguirá siendo útil para los visitantes, incluso si los enlaces se caen.
josliber
34

1. Establecer usuario global actual.

En su servicio de autenticación, configure el usuario autenticado actualmente en el ámbito raíz.

// AuthService.js

  // auth successful
  $rootScope.user = user

2. Configure la función de autenticación en cada ruta protegida.

// AdminController.js

.config(function ($routeProvider) {
  $routeProvider.when('/admin', {
    controller: 'AdminController',
    auth: function (user) {
      return user && user.isAdmin
    }
  })
})

3. Verifique la autenticación en cada cambio de ruta.

// index.js

.run(function ($rootScope, $location) {
  $rootScope.$on('$routeChangeStart', function (ev, next, curr) {
    if (next.$$route) {
      var user = $rootScope.user
      var auth = next.$$route.auth
      if (auth && !auth(user)) { $location.path('/') }
    }
  })
})

Alternativamente, puede establecer permisos en el objeto de usuario y asignar un permiso a cada ruta, luego verificar el permiso en la devolución de llamada del evento.

AJcodez
fuente
@malcolmhall, sí, esto es opt-in y usted desea optar por no participar. En su lugar, agregue un booleano "público" a las rutas públicas, como la página de inicio de sesión, y redirijaif (!user && !next.$$route.public)
AJcodez
¿Podría alguien explicarme next.$$route? No encuentro nada en los documentos angulares que describan los argumentos que dan a un $routeChangeStartevento, pero supongo nexty ¿ currhay algún tipo de objeto de ubicación? El $$routebit es difícil de google.
skagedal
2
Ahora veo que la $$routepropiedad es una variable privada de Angular. No debe confiar en eso, consulte por ejemplo: stackoverflow.com/a/19338518/1132101 : si lo hace, su código podría romperse cuando Angular cambie.
skagedal
2
He encontrado una manera de acceder a la ruta sin tener acceso a una propiedad privada o tener que recorrer $route.routespara construir una lista (como en la respuesta de @ thataustin): obtener la ruta de la ubicación con next.originalPathy el uso que para indexar $route.routes: var auth = $route.routes[next.originalPath].
skagedal
En cuanto a responder mi pregunta de hace tres comentarios sobre los argumentos que se dan al evento, parecen estar indocumentados, vea este tema que también hace referencia a esta pregunta SO: github.com/angular/angular.js/issues/ 10994
skagedal
27

Así es como lo hice, en caso de que ayude a alguien:

En la configuración, configuro un publicAccessatributo en las pocas rutas que quiero abrir al público (como iniciar sesión o registrarse):

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

luego, en un bloque de ejecución, configuro un escucha en el $routeChangeStartevento que redirige a '/login'menos que el usuario tenga acceso o la ruta sea de acceso público:

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');
        }
    });
})

Obviamente, podría cambiar la condición de isLoggedIncualquier otra cosa ... simplemente mostrando otra forma de hacerlo.

thataustin
fuente
y ¿cuál es el usuario en sus argumentos de bloque de ejecución? ¿un servicio?
mohamnag
sí, es un servicio que se encarga de las galletas de cheques, etc, para ver si el usuario ha iniciado sesión.
thataustin
Puede acceder a la ruta como por nextLoc.$$route.publicAccesscierto.
AJcodez
O use $route.routes[nextLoc.originalPath], que no usa una variable privada.
skagedal
1
En realidad, ¡puedes verificarlo nextLoc && nextLoc.publicAccess!
skagedal
9

Lo estoy haciendo usando interceptores. He creado un archivo de biblioteca que se puede agregar al archivo index.html. De esta manera, tendrá un manejo de errores global para sus llamadas de servicio de descanso y no tendrá que preocuparse por todos los errores individualmente. Más abajo también pegué mi biblioteca de inicio de sesión de autenticación básica. Allí puede ver que también verifico el error 401 y redirijo a una ubicación diferente. Ver lib / ea-basic-auth-login.js

lib / http-error-handling.js

/**
* @ngdoc overview
* @name http-error-handling
* @description
*
* Module that provides http error handling for apps.
*
* Usage:
* Hook the file in to your index.html: <script src="lib/http-error-handling.js"></script>
* Add <div class="messagesList" app-messages></div> to the index.html at the position you want to
* display the error messages.
*/
(function() {
'use strict';
angular.module('http-error-handling', [])
    .config(function($provide, $httpProvider, $compileProvider) {
        var elementsList = $();

        var showMessage = function(content, cl, time) {
            $('<div/>')
                .addClass(cl)
                .hide()
                .fadeIn('fast')
                .delay(time)
                .fadeOut('fast', function() { $(this).remove(); })
                .appendTo(elementsList)
                .text(content);
        };

        $httpProvider.responseInterceptors.push(function($timeout, $q) {
            return function(promise) {
                return promise.then(function(successResponse) {
                    if (successResponse.config.method.toUpperCase() != 'GET')
                        showMessage('Success', 'http-success-message', 5000);
                    return successResponse;

                }, function(errorResponse) {
                    switch (errorResponse.status) {
                        case 400:
                            showMessage(errorResponse.data.message, 'http-error-message', 6000);
                                }
                            }
                            break;
                        case 401:
                            showMessage('Wrong email or password', 'http-error-message', 6000);
                            break;
                        case 403:
                            showMessage('You don\'t have the right to do this', 'http-error-message', 6000);
                            break;
                        case 500:
                            showMessage('Server internal error: ' + errorResponse.data.message, 'http-error-message', 6000);
                            break;
                        default:
                            showMessage('Error ' + errorResponse.status + ': ' + errorResponse.data.message, 'http-error-message', 6000);
                    }
                    return $q.reject(errorResponse);
                });
            };
        });

        $compileProvider.directive('httpErrorMessages', function() {
            return {
                link: function(scope, element, attrs) {
                    elementsList.push($(element));
                }
            };
        });
    });
})();

css / http-error-handling.css

.http-error-message {
    background-color: #fbbcb1;
    border: 1px #e92d0c solid;
    font-size: 12px;
    font-family: arial;
    padding: 10px;
    width: 702px;
    margin-bottom: 1px;
}

.http-error-validation-message {
    background-color: #fbbcb1;
    border: 1px #e92d0c solid;
    font-size: 12px;
    font-family: arial;
    padding: 10px;
    width: 702px;
    margin-bottom: 1px;
}

http-success-message {
    background-color: #adfa9e;
    border: 1px #25ae09 solid;
    font-size: 12px;
    font-family: arial;
    padding: 10px;
    width: 702px;
    margin-bottom: 1px;
}

index.html

<!doctype html>
<html lang="en" ng-app="cc">
    <head>
        <meta charset="utf-8">
        <title>yourapp</title>
        <link rel="stylesheet" href="css/http-error-handling.css"/>
    </head>
    <body>

<!-- Display top tab menu -->
<ul class="menu">
  <li><a href="#/user">Users</a></li>
  <li><a href="#/vendor">Vendors</a></li>
  <li><logout-link/></li>
</ul>

<!-- Display errors -->
<div class="http-error-messages" http-error-messages></div>

<!-- Display partial pages -->
<div ng-view></div>

<!-- Include all the js files. In production use min.js should be used -->
<script src="lib/angular114/angular.js"></script>
<script src="lib/angular114/angular-resource.js"></script>
<script src="lib/http-error-handling.js"></script>
<script src="js/app.js"></script>
<script src="js/services.js"></script>
<script src="js/controllers.js"></script>
<script src="js/filters.js"></script>

lib / ea-basic-auth-login.js

Se puede hacer casi lo mismo para el inicio de sesión. Aquí tiene la respuesta a la redirección ($ location.path ("/ login")).

/**
* @ngdoc overview
* @name ea-basic-auth-login
* @description
*
* Module that provides http basic authentication for apps.
*
* Usage:
* Hook the file in to your index.html: <script src="lib/ea-basic-auth-login.js">  </script>
* Place <ea-login-form/> tag in to your html login page
* Place <ea-logout-link/> tag in to your html page where the user has to click to logout
*/
(function() {
'use strict';
angular.module('ea-basic-auth-login', ['ea-base64-login'])
    .config(['$httpProvider', function ($httpProvider) {
        var ea_basic_auth_login_interceptor = ['$location', '$q', function($location, $q) {
            function success(response) {
                return response;
            }

            function error(response) {
                if(response.status === 401) {
                    $location.path('/login');
                    return $q.reject(response);
                }
                else {
                    return $q.reject(response);
                }
            }

            return function(promise) {
                return promise.then(success, error);
            }
        }];
        $httpProvider.responseInterceptors.push(ea_basic_auth_login_interceptor);
    }])
    .controller('EALoginCtrl', ['$scope','$http','$location','EABase64Login', function($scope, $http, $location, EABase64Login) {
        $scope.login = function() {
            $http.defaults.headers.common['Authorization'] = 'Basic ' + EABase64Login.encode($scope.email + ':' + $scope.password);
            $location.path("/user");
        };

        $scope.logout = function() {
            $http.defaults.headers.common['Authorization'] = undefined;
            $location.path("/login");
        };
    }])
    .directive('eaLoginForm', [function() {
        return {
            restrict:   'E',
            template:   '<div id="ea_login_container" ng-controller="EALoginCtrl">' +
                        '<form id="ea_login_form" name="ea_login_form" novalidate>' +
                        '<input id="ea_login_email_field" class="ea_login_field" type="text" name="email" ng-model="email" placeholder="E-Mail"/>' +
                        '<br/>' +
                        '<input id="ea_login_password_field" class="ea_login_field" type="password" name="password" ng-model="password" placeholder="Password"/>' +
                        '<br/>' +
                        '<button class="ea_login_button" ng-click="login()">Login</button>' +
                        '</form>' +
                        '</div>',
            replace: true
        };
    }])
    .directive('eaLogoutLink', [function() {
        return {
            restrict: 'E',
            template: '<a id="ea-logout-link" ng-controller="EALoginCtrl" ng-click="logout()">Logout</a>',
            replace: true
        }
    }]);

angular.module('ea-base64-login', []).
    factory('EABase64Login', function() {
        var keyStr = 'ABCDEFGHIJKLMNOP' +
            'QRSTUVWXYZabcdef' +
            'ghijklmnopqrstuv' +
            'wxyz0123456789+/' +
            '=';

        return {
            encode: function (input) {
                var output = "";
                var chr1, chr2, chr3 = "";
                var enc1, enc2, enc3, enc4 = "";
                var i = 0;

                do {
                    chr1 = input.charCodeAt(i++);
                    chr2 = input.charCodeAt(i++);
                    chr3 = input.charCodeAt(i++);

                    enc1 = chr1 >> 2;
                    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                    enc4 = chr3 & 63;

                    if (isNaN(chr2)) {
                        enc3 = enc4 = 64;
                    } else if (isNaN(chr3)) {
                        enc4 = 64;
                    }

                    output = output +
                        keyStr.charAt(enc1) +
                        keyStr.charAt(enc2) +
                        keyStr.charAt(enc3) +
                        keyStr.charAt(enc4);
                    chr1 = chr2 = chr3 = "";
                    enc1 = enc2 = enc3 = enc4 = "";
                } while (i < input.length);

                return output;
            },

            decode: function (input) {
                var output = "";
                var chr1, chr2, chr3 = "";
                var enc1, enc2, enc3, enc4 = "";
                var i = 0;

                // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
                var base64test = /[^A-Za-z0-9\+\/\=]/g;
                if (base64test.exec(input)) {
                    alert("There were invalid base64 characters in the input text.\n" +
                        "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
                        "Expect errors in decoding.");
                }
                input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

                do {
                    enc1 = keyStr.indexOf(input.charAt(i++));
                    enc2 = keyStr.indexOf(input.charAt(i++));
                    enc3 = keyStr.indexOf(input.charAt(i++));
                    enc4 = keyStr.indexOf(input.charAt(i++));

                    chr1 = (enc1 << 2) | (enc2 >> 4);
                    chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                    chr3 = ((enc3 & 3) << 6) | enc4;

                    output = output + String.fromCharCode(chr1);

                    if (enc3 != 64) {
                        output = output + String.fromCharCode(chr2);
                    }
                    if (enc4 != 64) {
                        output = output + String.fromCharCode(chr3);
                    }

                    chr1 = chr2 = chr3 = "";
                    enc1 = enc2 = enc3 = enc4 = "";

                } while (i < input.length);

                return output;
            }
        };
    });
})();
Christopher Armstrong
fuente
2
Realmente deberías mantenerte alejado de la manipulación de dom en el JS a menos que estés en una directiva. Si solo configura su lógica y luego usa ng-class para aplicar una clase y desencadenar una animación CSS, se lo agradecerá más tarde.
Askdesigners
7

En su archivo app.js:

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

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

Es posible redirigir a otra vista con angular-ui-router . Para este propósito, tenemos el método $state.go("target_view"). Por ejemplo:

 ---- 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>
Jesús Castro
fuente
3

Si no desea utilizar angular-ui-router, pero desea que sus controladores se carguen de manera diferida a través de RequireJS, hay un par de problemas con el evento $routeChangeStart al usar sus controladores como módulos RequireJS (carga diferida).

No puede estar seguro de que el controlador se cargará antes de que $routeChangeStartse active; de ​​hecho, no se cargará. Eso significa que no puede acceder a propiedades de nextruta como localso $$routeporque aún no están configuradas.
Ejemplo:

app.config(["$routeProvider", function($routeProvider) {
    $routeProvider.when("/foo", {
        controller: "Foo",
        resolve: {
            controller: ["$q", function($q) {
                var deferred = $q.defer();
                require(["path/to/controller/Foo"], function(Foo) {
                    // now controller is loaded
                    deferred.resolve();
                });
                return deferred.promise;
            }]
        }
    });
}]);

app.run(["$rootScope", function($rootScope) {
    $rootScope.$on("$routeChangeStart", function(event, next, current) {
        console.log(next.$$route, next.locals); // undefined, undefined
    });
}]);

Esto significa que no puede verificar los derechos de acceso allí.

Solución:

Como la carga del controlador se realiza por resolución, puede hacer lo mismo con su control de control de acceso:

app.config(["$routeProvider", function($routeProvider) {
    $routeProvider.when("/foo", {
        controller: "Foo",
        resolve: {
            controller: ["$q", function($q) {
                var deferred = $q.defer();
                require(["path/to/controller/Foo"], function(Foo) {
                    // now controller is loaded
                    deferred.resolve();
                });
                return deferred.promise;
            }],
            access: ["$q", function($q) {
                var deferred = $q.defer();
                if (/* some logic to determine access is granted */) {
                    deferred.resolve();
                } else {
                    deferred.reject("You have no access rights to go there");
                }
                return deferred.promise;
            }],
        }
    });
}]);

app.run(["$rootScope", function($rootScope) {
    $rootScope.$on("$routeChangeError", function(event, next, current, error) {
        console.log("Error: " + error); // "Error: You have no access rights to go there"
    });
}]);

Tenga en cuenta aquí que en lugar de usar el evento $routeChangeStart, estoy usando$routeChangeError

Ivan Hušnjak
fuente
-4
    $routeProvider
 .when('/main' , {templateUrl: 'partials/main.html',  controller: MainController})
 .when('/login', {templateUrl: 'partials/login.html', controller: LoginController}).
 .when('/login', {templateUrl: 'partials/index.html', controller: IndexController})
 .otherwise({redirectTo: '/index'});
Dixit Hasija
fuente
Esta es una configuración de ruta básica ... ¿Dónde verificamos alguna condición antes de redirigir a las rutas configuradas?
TJ