Autenticación de inicio de sesión de enrutador ui AngularJS

376

Soy nuevo en AngularJS, y estoy un poco confundido acerca de cómo puedo usar angular- "ui-router" en el siguiente escenario:

Estoy creando una aplicación web que consta de dos secciones. La primera sección es la página de inicio con sus vistas de inicio de sesión y registro, y la segunda sección es el panel de control (después de un inicio de sesión exitoso).

He creado una index.htmlsección para la página de inicio con su aplicación angular y ui-routerconfiguración para manejar /loginy /signupvistas, y hay otro archivo dashboard.htmlpara la sección del tablero con su aplicación y ui-routerconfiguración para manejar muchas vistas secundarias.

Ahora terminé la sección del tablero y no sé cómo combinar las dos secciones con sus diferentes aplicaciones angulares. ¿Cómo podría decirle a la aplicación de inicio que redirija a la aplicación de tablero?

Ahmed Hashem
fuente
1
¿Puedes compartir algún código con nosotros?
Chancho
66
@Chancho Creo que no se trata de código, realmente no sé qué código debo compartir.
Ahmed Hashem
sí, por favor comparte el código, pregunta muy genérica ...
Alireza

Respuestas:

607

Estoy en el proceso de hacer una demostración más agradable y de limpiar algunos de estos servicios en un módulo utilizable, pero esto es lo que se me ocurrió. Este es un proceso complejo para evitar algunas advertencias, así que aguarde allí. Tendrás que dividir esto en varias partes.

Echa un vistazo a este golpe .

Primero, necesita un servicio para almacenar la identidad del usuario. Yo llamo a esto principal. Se puede verificar para ver si el usuario ha iniciado sesión y, si lo solicita, puede resolver un objeto que representa la información esencial sobre la identidad del usuario. Esto puede ser lo que necesite, pero lo esencial sería un nombre para mostrar, un nombre de usuario, posiblemente un correo electrónico y los roles a los que pertenece un usuario (si esto se aplica a su aplicación). El director también tiene métodos para hacer verificaciones de roles.

.factory('principal', ['$q', '$http', '$timeout',
  function($q, $http, $timeout) {
    var _identity = undefined,
      _authenticated = false;

    return {
      isIdentityResolved: function() {
        return angular.isDefined(_identity);
      },
      isAuthenticated: function() {
        return _authenticated;
      },
      isInRole: function(role) {
        if (!_authenticated || !_identity.roles) return false;

        return _identity.roles.indexOf(role) != -1;
      },
      isInAnyRole: function(roles) {
        if (!_authenticated || !_identity.roles) return false;

        for (var i = 0; i < roles.length; i++) {
          if (this.isInRole(roles[i])) return true;
        }

        return false;
      },
      authenticate: function(identity) {
        _identity = identity;
        _authenticated = identity != null;
      },
      identity: function(force) {
        var deferred = $q.defer();

        if (force === true) _identity = undefined;

        // check and see if we have retrieved the 
        // identity data from the server. if we have, 
        // reuse it by immediately resolving
        if (angular.isDefined(_identity)) {
          deferred.resolve(_identity);

          return deferred.promise;
        }

        // otherwise, retrieve the identity data from the
        // server, update the identity object, and then 
        // resolve.
        //           $http.get('/svc/account/identity', 
        //                     { ignoreErrors: true })
        //                .success(function(data) {
        //                    _identity = data;
        //                    _authenticated = true;
        //                    deferred.resolve(_identity);
        //                })
        //                .error(function () {
        //                    _identity = null;
        //                    _authenticated = false;
        //                    deferred.resolve(_identity);
        //                });

        // for the sake of the demo, fake the lookup
        // by using a timeout to create a valid
        // fake identity. in reality,  you'll want 
        // something more like the $http request
        // commented out above. in this example, we fake 
        // looking up to find the user is
        // not logged in
        var self = this;
        $timeout(function() {
          self.authenticate(null);
          deferred.resolve(_identity);
        }, 1000);

        return deferred.promise;
      }
    };
  }
])

En segundo lugar, necesita un servicio que verifique el estado al que quiere ir el usuario, se asegure de que haya iniciado sesión (si es necesario; no es necesario para iniciar sesión, restablecer la contraseña, etc.) y luego realice una verificación de roles (si su aplicación necesita esto). Si no están autenticados, envíelos a la página de inicio de sesión. Si están autenticados, pero fallan una verificación de roles, envíelos a una página de acceso denegado. Yo llamo a este servicio authorization.

.factory('authorization', ['$rootScope', '$state', 'principal',
  function($rootScope, $state, principal) {
    return {
      authorize: function() {
        return principal.identity()
          .then(function() {
            var isAuthenticated = principal.isAuthenticated();

            if ($rootScope.toState.data.roles
                && $rootScope.toState
                             .data.roles.length > 0 
                && !principal.isInAnyRole(
                   $rootScope.toState.data.roles))
            {
              if (isAuthenticated) {
                  // user is signed in but not
                  // authorized for desired state
                  $state.go('accessdenied');
              } else {
                // user is not authenticated. Stow
                // the state they wanted before you
                // send them to the sign-in state, so
                // you can return them when you're done
                $rootScope.returnToState
                    = $rootScope.toState;
                $rootScope.returnToStateParams
                    = $rootScope.toStateParams;

                // now, send them to the signin state
                // so they can log in
                $state.go('signin');
              }
            }
          });
      }
    };
  }
])

Ahora todo lo que necesitas hacer es escuchar en ui-router's $stateChangeStart. Esto le brinda la oportunidad de examinar el estado actual, el estado al que desean ir e insertar su verificación de autorización. Si falla, puede cancelar la transición de ruta o cambiar a una ruta diferente.

.run(['$rootScope', '$state', '$stateParams', 
      'authorization', 'principal',
    function($rootScope, $state, $stateParams, 
             authorization, principal)
{
      $rootScope.$on('$stateChangeStart', 
          function(event, toState, toStateParams)
      {
        // track the state the user wants to go to; 
        // authorization service needs this
        $rootScope.toState = toState;
        $rootScope.toStateParams = toStateParams;
        // if the principal is resolved, do an 
        // authorization check immediately. otherwise,
        // it'll be done when the state it resolved.
        if (principal.isIdentityResolved()) 
            authorization.authorize();
      });
    }
  ]);

La parte difícil de rastrear la identidad de un usuario es buscarlo si ya se ha autenticado (por ejemplo, está visitando la página después de una sesión anterior y ha guardado un token de autenticación en una cookie, o tal vez ha actualizado una página, o cayó en una URL desde un enlace). Debido a la forma en que ui-routerfunciona, debe resolver su identidad una vez, antes de verificar su autenticación. Puede hacerlo utilizando la resolveopción en la configuración de su estado. Tengo un estado principal para el sitio del que todos los estados heredan, lo que obliga al director a resolverse antes de que ocurra cualquier otra cosa.

$stateProvider.state('site', {
  'abstract': true,
  resolve: {
    authorize: ['authorization',
      function(authorization) {
        return authorization.authorize();
      }
    ]
  },
  template: '<div ui-view />'
})

Hay otro problema aquí ... resolvesolo se llama una vez. Una vez que su promesa de búsqueda de identidad se complete, no volverá a ejecutar el delegado de resolución. Por lo tanto, tenemos que hacer sus comprobaciones de autenticación en dos lugares: una vez de acuerdo con la resolución de su promesa de identidad resolve, que cubre la primera vez que se carga su aplicación, y una vez $stateChangeStartsi la resolución se ha realizado, que cubre cualquier momento que navegue por los estados.

Bien, ¿qué hemos hecho hasta ahora?

  1. Verificamos cuándo se carga la aplicación si el usuario ha iniciado sesión.
  2. Rastreamos información sobre el usuario conectado.
  3. Los redirigimos al estado de inicio de sesión para los estados que requieren que el usuario inicie sesión.
  4. Los redirigimos a un estado de acceso denegado si no tienen autorización para acceder a él.
  5. Tenemos un mecanismo para redirigir a los usuarios al estado original que solicitaron, si necesitáramos que inicien sesión.
  6. Podemos cerrar la sesión de un usuario (debe conectarse por cable con cualquier código de cliente o servidor que administre su ticket de autenticación).
  7. Nosotros no tenemos que enviar a los usuarios volver a la página de registro cada vez que vuelva a cargar el navegador o la abandonan en un enlace.

¿A dónde vamos desde aquí? Bueno, se puede organizar sus estados en regiones que requieren inicio de sesión. Puede requerir que los usuarios autenticados / autorizados mediante la adición datade rolesestos estados (o uno de los padres de ellos, si desea utilizar la herencia). Aquí, restringimos un recurso a los administradores:

.state('restricted', {
    parent: 'site',
    url: '/restricted',
    data: {
      roles: ['Admin']
    },
    views: {
      'content@': {
        templateUrl: 'restricted.html'
      }
    }
  })

Ahora puede controlar estado por estado a qué usuarios pueden acceder una ruta. ¿Alguna otra inquietud? ¿Tal vez variar solo una parte de una vista en función de si están o no conectados? No hay problema. Use principal.isAuthenticated()o incluso principal.isInRole()con cualquiera de las numerosas formas en que puede mostrar condicionalmente una plantilla o un elemento.

Primero, inyecte principalen un controlador o lo que sea, y adhiéralo al alcance para que pueda usarlo fácilmente desde su punto de vista:

.scope('HomeCtrl', ['$scope', 'principal', 
    function($scope, principal)
{
  $scope.principal = principal;
});

Mostrar u ocultar un elemento:

<div ng-show="principal.isAuthenticated()">
   I'm logged in
</div>
<div ng-hide="principal.isAuthenticated()">
  I'm not logged in
</div>

Etc., etc., etc. De todos modos, en su aplicación de ejemplo, tendría un estado para la página de inicio que permitiría la visita de usuarios no autenticados. Podrían tener enlaces a los estados de inicio o inicio de sesión, o tener esos formularios integrados en esa página. Lo que te venga bien.

Todas las páginas del panel podrían heredarse de un estado que requiere que los usuarios inicien sesión y, digamos, sean Usermiembros del rol. Todas las cosas de autorización que hemos discutido fluirían desde allí.

moribvndvs
fuente
28
Gracias, esto realmente me ayudó a reunir mi propio código. En una nota al margen, si obtienes un bucle de enrutamiento infinito (error de enrutador UI), prueba en $location.pathlugar de $state.go.
jvannistelrooy
2
Esta es una gran respuesta y me ha ayudado mucho. Cuando configuro user = principal en mi controlador e intento llamar a say user.identity (). Name en mi vista para obtener el nombre de usuario actualmente conectado, parece que solo obtengo el objeto de promesa {entonces: fn, catch: fn, finalmente :} devuelto y no el objeto _identity real. Si uso user.identity.then (fn (usuario)) puedo obtener el objeto de usuario, pero esto parece una gran cantidad de código para la vista ¿Me estoy perdiendo algo?
Mark
44
@ Ir1sh Resolvería la identidad primero en el controlador y se la asignaría a $scope.usersu thenfunción. Todavía puede hacer referencia useren sus puntos de vista; cuando se resuelva, la vista se actualizará.
moribvndvs
2
@HackedByChinese Creo que tu demo ya no funciona.
Blowsie 01 de
77
@jvannistelrooy Tuve problemas con go () to, pero después de ponerlo dentro de él luego de llamar a una función noop como esta $q.when(angular.noop).then(function(){$state.go('myState'), todo funciona como se esperaba. Si llamo $state.gomientras no se completa otra transición de estado, entonces no funcionará (creo que esa es la razón por la que no funcionará).
Sebastian
120

Las soluciones publicadas hasta ahora son innecesariamente complicadas, en mi opinión. Hay una manera más simple. La documentación deui-router dice escuchar $locationChangeSuccessy usar $urlRouter.sync()para verificar una transición de estado, detenerla o reanudarla. Pero incluso eso en realidad no funciona.

Sin embargo, aquí hay dos alternativas simples. Elegir uno:

Solución 1: escuchando $locationChangeSuccess

Puede escuchar $locationChangeSuccessy puede realizar algo de lógica, incluso lógica asincrónica allí. De acuerdo con esa lógica, puede dejar que la función regrese indefinida, lo que hará que la transición de estado continúe de manera normal, o puede hacerlo $state.go('logInPage'), si el usuario necesita ser autenticado. Aquí hay un ejemplo:

angular.module('App', ['ui.router'])

// In the run phase of your Angular application  
.run(function($rootScope, user, $state) {

  // Listen to '$locationChangeSuccess', not '$stateChangeStart'
  $rootScope.$on('$locationChangeSuccess', function() {
    user
      .logIn()
      .catch(function() {
        // log-in promise failed. Redirect to log-in page.
        $state.go('logInPage')
      })
  })
})

Tenga en cuenta que esto en realidad no impide que se cargue el estado de destino, pero sí redirige a la página de inicio de sesión si el usuario no está autorizado. Eso está bien, ya que la protección real está en el servidor, de todos modos.

Solución 2: usar estado resolve

En esta solución, utiliza la ui-routerfunción de resolución .

Básicamente rechaza la promesa resolvesi el usuario no está autenticado y luego lo redirige a la página de inicio de sesión.

Así es como va:

angular.module('App', ['ui.router'])

.config(
  function($stateProvider) {
    $stateProvider
      .state('logInPage', {
        url: '/logInPage',
        templateUrl: 'sections/logInPage.html',
        controller: 'logInPageCtrl',
      })
      .state('myProtectedContent', {
        url: '/myProtectedContent',
        templateUrl: 'sections/myProtectedContent.html',
        controller: 'myProtectedContentCtrl',
        resolve: { authenticate: authenticate }
      })
      .state('alsoProtectedContent', {
        url: '/alsoProtectedContent',
        templateUrl: 'sections/alsoProtectedContent.html',
        controller: 'alsoProtectedContentCtrl',
        resolve: { authenticate: authenticate }
      })

    function authenticate($q, user, $state, $timeout) {
      if (user.isAuthenticated()) {
        // Resolve the promise successfully
        return $q.when()
      } else {
        // The next bit of code is asynchronously tricky.

        $timeout(function() {
          // This code runs after the authentication promise has been rejected.
          // Go to the log-in page
          $state.go('logInPage')
        })

        // Reject the authentication promise to prevent the state from loading
        return $q.reject()
      }
    }
  }
)

A diferencia de la primera solución, esta solución realmente evita que se cargue el estado objetivo.

MK Safi
fuente
66
@FredLackey dice que hay usuarios no autenticados state A. Hacen clic en un enlace para ir protected state Bpero desea redirigirlos logInPage. Si no hay $timeout, ui-routersimplemente detendrá todas las transiciones de estado, para que el usuario quede atrapado state A. Esto $timeoutpermite ui-routerevitar primero la transición inicial protected state Bporque la resolución fue rechazada y, una vez hecho, redirige a logInPage.
MK Safi
¿Dónde se authenticatellama realmente la función?
CodyBugstein
La authenticatefunción @Imray se pasa como parámetro a ui-router. No tienes que llamarlo tú mismo. ui-routerlo llama
MK Safi
¿Por qué estás usando '$ locationChangeSuccess' en lugar de '$ stateChangeStart'?
Draex_
@ PeterDraexDräxler Estaba siguiendo principalmente la documentación. ¿Notaste alguna diferencia al usar $stateChangeStart?
MK Safi
42

La solución más fácil es usar $stateChangeStarty event.preventDefault()cancelar el cambio de estado cuando el usuario no está autenticado y redirigirlo al estado de autenticación que es la página de inicio de sesión.

angular
  .module('myApp', [
    'ui.router',
  ])
    .run(['$rootScope', 'User', '$state',
    function ($rootScope, User, $state) {
      $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) {
        if (toState.name !== 'auth' && !User.authenticaded()) {
          event.preventDefault();
          $state.go('auth');
        }
      });
    }]
  );
sebest
fuente
66
No creo que esto funcione si User.authenticaded () es una llamada asincrónica. Ese es el santo grial que todos buscan. Por ejemplo, si todos los estados excepto "inicio de sesión" están asegurados, quiero confirmar que el usuario todavía está autenticado ANTES de cargar cualquier estado. El uso de resolver apesta porque solo se resuelve una vez, y para evitar que los estados secundarios se carguen, debe inyectar la resolución en CADA NIÑO .
Jason
autenticado no es una llamada asíncrona en mi caso: `this.authenticaded = function () {if (this.currentAccountID! == null) {return true; } falso retorno; }; `
sebest
Según: stackoverflow.com/a/38374313/849829 , 'ejecutar' está muy por encima de 'servicio' y, por lo tanto, los problemas. Verificar el almacenamiento local para el estado autenticado parece ser un buen enfoque.
Deepak Thomas
22

Creo que necesita un serviceque maneje el proceso de autenticación (y su almacenamiento).

En este servicio necesitarás algunos métodos básicos:

  • isAuthenticated()
  • login()
  • logout()
  • etc ...

Este servicio debe inyectarse en sus controladores de cada módulo:

  • En la sección de su tablero, use este servicio para verificar si el usuario está autenticado ( service.isAuthenticated()método). si no, redirigir a / iniciar sesión
  • En su sección de inicio de sesión, simplemente use los datos del formulario para autenticar al usuario a través de su service.login()método

Un buen y robusto ejemplo de este comportamiento es la aplicación angular del proyecto y específicamente su módulo de seguridad que se basa en el impresionante Módulo Interceptor de Autenticación HTTP

Espero que esto ayude

Cétia
fuente
21

Creé este módulo para ayudar a que este proceso sea sencillo

Puedes hacer cosas como:

$routeProvider
  .state('secret',
    {
      ...
      permissions: {
        only: ['admin', 'god']
      }
    });

O tambien

$routeProvider
  .state('userpanel',
    {
      ...
      permissions: {
        except: ['not-logged-in']
      }
    });

¡Es nuevo pero vale la pena echarle un vistazo!

https://github.com/Narzerus/angular-permission

Rafael Vidaurre
fuente
2
¿Qué me impide editar la fuente en tiempo de ejecución y eliminar su 'admin' || 'dios' y continua?
Pogrindis
12
Espero que cualquier solicitud de datos que requiera autorización también se verifique en el servidor.
Ben Ripley
24
Esto no está destinado a la seguridad, la autorización del lado del cliente nunca es así, ya que siempre puede cambiar los valores. Incluso podría interceptar las respuestas del lado del servidor y evaluarlas como "autorizadas". El punto de los permisos / autorizaciones en el lado del cliente es evitar que el usuario haga cosas prohibidas con fines de UX. Por ejemplo, si está manejando una acción solo de administrador, incluso si el usuario engaña maliciosamente al cliente para permitir el envío de una solicitud restringida al servidor, el servidor aún devolverá una respuesta 401. Esto, por supuesto, siempre es responsabilidad de la API que se está implementando @BenRipley, de hecho
Rafael Vidaurre
3
Gran respuesta a la pregunta de Rafael. Siempre proteja la API porque el front-end es la cosa más ingeniosa y engañosa que existe.
Frankie Loscavio
1
Este problema con el historial se resuelve desde hace bastante tiempo ahora @Bohdan. Puede usarlo de manera segura incluso con extras de enrutador ui.
masterspambot
16

Quería compartir otra solución trabajando con el enrutador ui 1.0.0.X

Como ya sabrás, stateChangeStart y stateChangeSuccess ahora están en desuso. https://github.com/angular-ui/ui-router/issues/2655

En su lugar, debe usar $ transitions http://angular-ui.github.io/ui-router/1.0.0-alpha.1/interfaces/transition.ihookregistry.html

Así es como lo logré:

Primero tengo y AuthService con algunas funciones útiles

angular.module('myApp')

        .factory('AuthService',
                ['$http', '$cookies', '$rootScope',
                    function ($http, $cookies, $rootScope) {
                        var service = {};

                        // Authenticates throug a rest service
                        service.authenticate = function (username, password, callback) {

                            $http.post('api/login', {username: username, password: password})
                                    .success(function (response) {
                                        callback(response);
                                    });
                        };

                        // Creates a cookie and set the Authorization header
                        service.setCredentials = function (response) {
                            $rootScope.globals = response.token;

                            $http.defaults.headers.common['Authorization'] = 'Bearer ' + response.token;
                            $cookies.put('globals', $rootScope.globals);
                        };

                        // Checks if it's authenticated
                        service.isAuthenticated = function() {
                            return !($cookies.get('globals') === undefined);
                        };

                        // Clear credentials when logout
                        service.clearCredentials = function () {
                            $rootScope.globals = undefined;
                            $cookies.remove('globals');
                            $http.defaults.headers.common.Authorization = 'Bearer ';
                        };

                        return service;
                    }]);

Entonces tengo esta configuración:

angular.module('myApp', [
    'ui.router',
    'ngCookies'
])
        .config(['$stateProvider', '$urlRouterProvider',
            function ($stateProvider, $urlRouterProvider) {
                $urlRouterProvider.otherwise('/resumen');
                $stateProvider
                        .state("dashboard", {
                            url: "/dashboard",
                            templateUrl: "partials/dashboard.html",
                            controller: "dashCtrl",
                            data: {
                                authRequired: true
                            }
                        })
                        .state("login", {
                            url: "/login",
                            templateUrl: "partials/login.html",
                            controller: "loginController"
                        })
            }])

        .run(['$rootScope', '$transitions', '$state', '$cookies', '$http', 'AuthService',
            function ($rootScope, $transitions, $state, $cookies, $http, AuthService) {

                // keep user logged in after page refresh
                $rootScope.globals = $cookies.get('globals') || {};
                $http.defaults.headers.common['Authorization'] = 'Bearer ' + $rootScope.globals;

                $transitions.onStart({
                    to: function (state) {
                        return state.data != null && state.data.authRequired === true;
                    }
                }, function () {
                    if (!AuthService.isAuthenticated()) {
                        return $state.target("login");
                    }
                });
            }]);

Puedes ver que yo uso

data: {
   authRequired: true
}

para marcar el estado solo accesible si está autenticado.

luego, en el .run uso las transiciones para verificar el estado autenticado

$transitions.onStart({
    to: function (state) {
        return state.data != null && state.data.authRequired === true;
    }
}, function () {
    if (!AuthService.isAuthenticated()) {
        return $state.target("login");
    }
});

Construyo este ejemplo usando algún código que se encuentra en la documentación de $ transitions. Soy bastante nuevo con el enrutador ui pero funciona.

Espero que pueda ayudar a cualquiera.

Sergio Fernández
fuente
Esto es ideal para aquellos que usan el enrutador más nuevo. ¡Gracias!
mtro
5

Así es como salimos del bucle de enrutamiento infinito y todavía lo usamos en $state.golugar de$location.path

if('401' !== toState.name) {
  if (principal.isIdentityResolved()) authorization.authorize();
}
Jason Girdner
fuente
1
¿Alguien sabe por qué al usar la respuesta / configuración aceptada descrita anteriormente, la barra de direcciones ya no muestra la URL y todos los fragmentos y parámetros de cadena de consulta? Desde la implementación de esto, la barra de direcciones ya no permite que nuestra aplicación se marque como favorita.
Frankie Loscavio
1
¿No se supone que esto es un comentario sobre una de las respuestas existentes? Debido a que no existe dicho código en OP y ni siquiera está claro a qué respuesta / a qué código se refiere esto
TJ
3

Tengo otra solución: esa solución funciona perfectamente cuando solo tiene contenido que desea mostrar cuando está conectado. Defina una regla en la que verifique si está conectado y no la ruta de las rutas de la lista blanca.

$urlRouterProvider.rule(function ($injector, $location) {
   var UserService = $injector.get('UserService');
   var path = $location.path(), normalized = path.toLowerCase();

   if (!UserService.isLoggedIn() && path.indexOf('login') === -1) {
     $location.path('/login/signin');
   }
});

En mi ejemplo, pregunto si no he iniciado sesión y la ruta actual que quiero enrutar no es parte de `/ login ', porque mis rutas de la lista blanca son las siguientes

/login/signup // registering new user
/login/signin // login to app

así que tengo acceso instantáneo a estas dos rutas y se comprobará cualquier otra ruta si está en línea.

Aquí está todo mi archivo de enrutamiento para el módulo de inicio de sesión

export default (
  $stateProvider,
  $locationProvider,
  $urlRouterProvider
) => {

  $stateProvider.state('login', {
    parent: 'app',
    url: '/login',
    abstract: true,
    template: '<ui-view></ui-view>'
  })

  $stateProvider.state('signin', {
    parent: 'login',
    url: '/signin',
    template: '<login-signin-directive></login-signin-directive>'
  });

  $stateProvider.state('lock', {
    parent: 'login',
    url: '/lock',
    template: '<login-lock-directive></login-lock-directive>'
  });

  $stateProvider.state('signup', {
    parent: 'login',
    url: '/signup',
    template: '<login-signup-directive></login-signup-directive>'
  });

  $urlRouterProvider.rule(function ($injector, $location) {
    var UserService = $injector.get('UserService');
    var path = $location.path();

    if (!UserService.isLoggedIn() && path.indexOf('login') === -1) {
         $location.path('/login/signin');
    }
  });

  $urlRouterProvider.otherwise('/error/not-found');
}

() => { /* code */ } es la sintaxis de ES6, use en su lugar function() { /* code */ }

Chris Incoqnito
fuente
3

Use $ http Interceptor

Mediante el uso de un interceptor $ http, puede enviar encabezados a Back-end o al revés y hacer sus comprobaciones de esa manera.

Gran artículo sobre interceptores $ http

Ejemplo:

$httpProvider.interceptors.push(function ($q) {
        return {
            'response': function (response) {

                // TODO Create check for user authentication. With every request send "headers" or do some other check
                return response;
            },
            'responseError': function (reject) {

                // Forbidden
                if(reject.status == 403) {
                    console.log('This page is forbidden.');
                    window.location = '/';
                // Unauthorized
                } else if(reject.status == 401) {
                    console.log("You're not authorized to view this page.");
                    window.location = '/';
                }

                return $q.reject(reject);
            }
        };
    });

Ponga esto en su función .config o .run.

TSlegaitis
fuente
2

Primero necesitará un servicio que pueda inyectar en sus controladores que tenga alguna idea del estado de autenticación de la aplicación. Los detalles de autenticación persistentes con almacenamiento local son una forma decente de abordarlo.

A continuación, deberá verificar el estado de autenticación justo antes de los cambios de estado. Dado que su aplicación tiene algunas páginas que deben autenticarse y otras que no, cree una ruta principal que verifique la autenticación y haga que todas las demás páginas que requieren la misma sean secundarias de ese padre.

Finalmente, necesitará alguna forma de saber si su usuario actualmente conectado puede realizar ciertas operaciones. Esto se puede lograr agregando una función 'can' a su servicio de autenticación. Can toma dos parámetros: - acción - requerido - (es decir, 'manage_dashboards' o 'create_new_dashboard') - objeto - opcional - objeto en el que se opera. Por ejemplo, si tenía un objeto de tablero, es posible que desee verificar si dashboard.ownerId === loginInUser.id. (Por supuesto, la información transmitida por el cliente nunca debe ser confiable y siempre debe verificarla en el servidor antes de escribirla en su base de datos).

angular.module('myApp', ['ngStorage']).config([
   '$stateProvider',
function(
   $stateProvider
) {
   $stateProvider
     .state('home', {...}) //not authed
     .state('sign-up', {...}) //not authed
     .state('login', {...}) //not authed
     .state('authed', {...}) //authed, make all authed states children
     .state('authed.dashboard', {...})
}])
.service('context', [
   '$localStorage',
function(
   $localStorage
) {
   var _user = $localStorage.get('user');
   return {
      getUser: function() {
         return _user;
      },
      authed: function() {
         return (_user !== null);
      },
      // server should return some kind of token so the app 
      // can continue to load authenticated content without having to
      // re-authenticate each time
      login: function() {
         return $http.post('/login.json').then(function(reply) {
            if (reply.authenticated === true) {
               $localStorage.set(_userKey, reply.user);
            }
         });
      },
      // this request should expire that token, rendering it useless
      // for requests outside of this session
      logout: function() {
         return $http.post('logout.json').then(function(reply) {
            if (reply.authenticated === true) {
               $localStorage.set(_userKey, reply.user);
            }
         });
      },
      can: function(action, object) {
         if (!this.authed()) {
            return false;
         }

         var user = this.getUser();

         if (user && user.type === 'admin') {
             return true;
         }

         switch(action) {
            case 'manage_dashboards':
               return (user.type === 'manager');
         }

         return false;


      }
   }
}])
.controller('AuthCtrl', [
   'context', 
   '$scope', 
function(
   context, 
   $scope
) {
   $scope.$root.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
      //only require auth if we're moving to another authed page
      if (toState && toState.name.indexOf('authed') > -1) {
         requireAuth();
      }
   });

   function requireAuth() {
      if (!context.authed()) {
         $state.go('login');
      }
   }
}]

** DESCARGO DE RESPONSABILIDAD: El código anterior es un seudocódigo y viene sin garantías **

colefner
fuente