¿Cómo almaceno un contexto de usuario actual en AngularJS?

92

Tengo un AuthService, que inicia sesión en un usuario, devuelve un objeto json de usuario. Lo que quiero hacer es configurar ese objeto y que todos los cambios se reflejen en la aplicación (estado de inicio / cierre de sesión) sin tener que actualizar la página.

¿Cómo podría lograr esto con AngularJS?

Arte
fuente

Respuestas:

180

La forma más sencilla de lograrlo es mediante un servicio. Por ejemplo:

app.factory( 'AuthService', function() {
  var currentUser;

  return {
    login: function() { ... },
    logout: function() { ... },
    isLoggedIn: function() { ... },
    currentUser: function() { return currentUser; }
    ...
  };
});

A continuación, puede hacer referencia a esto en cualquiera de sus controladores. El siguiente código busca cambios en un valor del servicio (llamando a la función especificada) y luego sincroniza los valores modificados con el alcance.

app.controller( 'MainCtrl', function( $scope, AuthService ) {
  $scope.$watch( AuthService.isLoggedIn, function ( isLoggedIn ) {
    $scope.isLoggedIn = isLoggedIn;
    $scope.currentUser = AuthService.currentUser();
  });
});

Y luego, por supuesto, puede usar esa información como mejor le parezca; por ejemplo, en directivas, en plantillas, etc. Puede repetir esto (personalizado según lo que necesite hacer) en sus controladores de menú, etc. Todo se actualizará automáticamente cuando cambie el estado del servicio.

Cualquier cosa más específica depende de su implementación.

¡Espero que esto ayude!

Josh David Miller
fuente
28
@ChrisNicola En realidad, en AngularJS todos los servicios son singletons. Por lo tanto, el servicio se crea la primera vez que se solicita (es decir, un controlador u otro servicio) y todas las solicitudes posteriores devuelven exactamente la misma instancia.
Josh David Miller
2
Podría ser, pero como una función podemos eliminar los aspectos internos de cómo almacenamos esa información de la API pública y en la API privada. Esto hace que la refactorización posterior sea mucho más sencilla. Pero la función aún devolvería un booleano.
Josh David Miller
7
Esta podría ser una pregunta estúpida ... pero ¿qué sucede si el usuario actualiza la página? ¿Se pierde la información de inicio de sesión?
Tomba
10
@Tomba Esa es una buena pregunta. :-) De hecho, la información se pierde al actualizar. Por lo general, tendrá que almacenar cierta información de la sesión en una cookie. La información de esa sesión también se puede verificar al configurar el AuthService. Esto ayuda no solo para las actualizaciones de la página, sino también para alguien que abre un enlace en una nueva pestaña.
Josh David Miller
2
@PixMach Tiene toda la razón sobre la curva de aprendizaje. Su pregunta dependerá mucho del caso específico, pero aquí hay algunos patrones generales. Mantenga la separación de preocupaciones: la interfaz de usuario relacionada con el inicio de un inicio de sesión está separada de la autenticación en sí, que está separada del estado de la autenticación, que está separada de cualquier menú que pueda depender de dicho estado. Nav / menu a menudo se manejan mejor con un solo controlador, y los estados anidados (a la ui-router) y las resoluciones de ruta son una buena manera de mantener los controles de autenticación SECOS. Lo que escribiste suena bien.
Josh David Miller
5

Enmendaría la buena respuesta de Josh agregando que, dado que un AuthService suele interesar a cualquiera (digamos, cualquiera que no sea la vista de inicio de sesión debería desaparecer si nadie está registrado), tal vez una alternativa más sencilla sería notificar a las partes interesadas mediante $rootScope.$broadcast('loginStatusChanged', isLoggedIn);(1 ) (2), mientras que las partes interesadas (como los controladores) escucharían utilizando $scope.$on('loginStatusChanged', function (event, isLoggedIn) { $scope.isLoggedIn = isLoggedIn; }.

(1) $rootScopesiendo inyectado como argumento del servicio

(2) Tenga en cuenta que, en el caso probable de una operación de inicio de sesión asincrónica, querrá notificar a Angular que la transmisión cambiará las cosas, incluyéndola en una $rootScope.$apply()función.

Ahora, hablando de mantener el contexto del usuario en todos / muchos controladores, es posible que no esté contento de escuchar los cambios de inicio de sesión en todos ellos, y es posible que prefiera escuchar solo en un controlador de inicio de sesión superior y luego agregar otros controladores con reconocimiento de inicio de sesión como niños / controladores integrados de este. De esta manera, el controlador secundario podrá ver las propiedades $ scope heredadas del padre, como su contexto de usuario.

Javarome
fuente
4
Votado en contra por explicación incorrecta de la función de fábrica. Este malentendido ya se abordó en este comentario meses antes de que publicara su respuesta.
Rhys van der Waerden