Wie speichere ich einen aktuellen Benutzerkontext in AngularJS?

92

Ich habe einen AuthService, der einen Benutzer anmeldet und ein Benutzer-JSON-Objekt zurückgibt. Ich möchte dieses Objekt festlegen und alle Änderungen in der gesamten Anwendung widerspiegeln (angemeldeter / abgemeldeter Status), ohne die Seite aktualisieren zu müssen.

Wie würde ich das mit AngularJS erreichen?

Kunst
quelle

Antworten:

180

Der einfachste Weg, dies zu erreichen, ist die Verwendung eines Dienstes. Beispielsweise:

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

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

Sie können dies dann in jedem Ihrer Controller referenzieren. Der folgende Code sucht nach Änderungen an einem Wert des Dienstes (durch Aufrufen der angegebenen Funktion) und synchronisiert dann die geänderten Werte mit dem Bereich.

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

Und dann können Sie diese Informationen natürlich verwenden, wie Sie es für richtig halten. zB in Direktiven, in Vorlagen usw. Sie können dies (angepasst an Ihre Anforderungen) in Ihren Menü-Controllern usw. wiederholen. Alles wird automatisch aktualisiert, wenn Sie den Status des Dienstes ändern.

Alles Spezifische hängt von Ihrer Implementierung ab.

Hoffe das hilft!

Josh David Miller
quelle
28
@ChrisNicola Tatsächlich sind in AngularJS alle Dienste Singletons. Der Dienst wird also beim ersten Anfordern erstellt (dh von einem Controller oder einem anderen Dienst), und alle nachfolgenden Anforderungen für ihn geben genau dieselbe Instanz zurück.
Josh David Miller
2
Es könnte sein, aber als Funktion können wir die Interna entfernen, wie wir diese Informationen aus der öffentlichen API in die private API speichern. Dies erleichtert das spätere Refactoring erheblich. Aber die Funktion würde immer noch zurückkehren einen boolean.
Josh David Miller
7
Dies mag eine dumme Frage sein ... aber was passiert, wenn der Benutzer die Seite aktualisiert - gehen die Anmeldeinformationen verloren?
Tomba
10
@Tomba Das ist eine gute Frage. :-) Tatsächlich gehen die Informationen beim Aktualisieren verloren. Normalerweise möchten Sie einige Sitzungsinformationen in einem Cookie speichern . Diese Sitzungsinformationen können auch beim Einrichten der überprüft werden AuthService. Dies hilft nicht nur bei Seitenaktualisierungen, sondern auch bei Personen, die einen Link in einem neuen Tab öffnen.
Josh David Miller
2
@PixMach Sie haben 100% Recht mit der Lernkurve. Ihre Frage wird stark vom konkreten Fall abhängen, aber hier sind einige allgemeine Muster. Beibehaltung der Trennung von Bedenken: Die Benutzeroberfläche zum Initiieren einer Anmeldung ist von der Authentifizierung selbst getrennt, die vom Status der Authentifizierung getrennt ist, der von allen Menüs getrennt ist, die von diesem Status abhängen können. Navigation / Menü werden häufig am besten von einem einzelnen Controller verwaltet, und verschachtelte Status (a la ui-router) und Routenauflösungen sind eine gute Möglichkeit, die Authentifizierungssteuerung trocken zu halten. Was Sie geschrieben haben, klingt ungefähr richtig.
Josh David Miller
5

Ich würde die gute Antwort von Josh ändern, indem ich hinzufüge, dass, da ein AuthService normalerweise für jeden von Interesse ist (z. B. sollte jeder außer der Anmeldeansicht verschwinden, wenn niemand angemeldet ist), eine einfachere Alternative darin besteht, interessierte Parteien mit $rootScope.$broadcast('loginStatusChanged', isLoggedIn);(1) zu benachrichtigen ) (2), während interessierte Parteien (wie Controller) mit zuhören würden $scope.$on('loginStatusChanged', function (event, isLoggedIn) { $scope.isLoggedIn = isLoggedIn; }.

(1) $rootScopeals Argument des Dienstes injiziert werden

(2) Beachten Sie, dass Sie Angular im wahrscheinlichen Fall eines asynchronen Anmeldevorgangs benachrichtigen möchten, dass die Übertragung Änderungen ändert, indem Sie sie in eine $rootScope.$apply()Funktion aufnehmen.

Wenn Sie nun davon sprechen, den Benutzerkontext in jedem / vielen Controllern beizubehalten, sind Sie möglicherweise nicht glücklich, auf Anmeldeänderungen in jedem von ihnen zu warten, und ziehen es möglicherweise vor, nur in einem obersten Login-Controller zu lauschen und dann andere login-fähige Controller als untergeordnete Controller hinzuzufügen. eingebettete Controller von diesem. Auf diese Weise kann der untergeordnete Controller die geerbten übergeordneten $ scope-Eigenschaften wie Ihren Benutzerkontext anzeigen.

Javarome
quelle
4
Für falsche Erklärung der Werksfunktion herabgestimmt. Dieses Missverständnis wurde bereits Monate vor der Veröffentlichung Ihrer Antwort in diesem Kommentar behoben.
Rhys van der Waerden