Eckige 4 - canActivate beobachtbaren nicht aufgerufen werden
Bin ich versucht zu implementieren canActivate
im Winkel 2/4 mit RxJS observablen. Ich habe schon gelesen eine andere Frage auf dieser. Mit dem folgenden code, der meine canActivate
Methode funktioniert nur einmal, wenn die app startet, aber hello
ist nie wieder gedruckt, wenn die isLoggedIn
beobachtbaren löst neue Werte.
canActivate(): Observable<boolean> {
return this.authService.isLoggedIn().map(isLoggedIn => {
console.log('hello');
if (!isLoggedIn) {
this.router.navigate(['/login']);
}
return isLoggedIn;
}).first();
}
oder diese version ist nicht so gut funktioniert:
canActivate(): Observable<boolean> {
return this.authService.isLoggedIn().map(isLoggedIn => {
console.log('hello');
if (isLoggedIn) {
this.router.navigate(['/']);
}
return !isLoggedIn;
});
}
Aber es funktioniert gut mit diesem code:
canActivate(): Observable<boolean> {
return Observable.create(obs => {
this.authService.isLoggedIn().map(isLoggedIn => {
console.log('hello');
if (isLoggedIn) {
this.router.navigate(['/']);
}
return !isLoggedIn;
}).subscribe(isLoggedIn => obs.next(isLoggedIn));
});
}
Was mache ich falsch, im ersten Stück code ?
EDIT: hier ist der isLoggedIn
Umsetzung
@LocalStorage(AuthService.JWT_TOKEN_KEY)
private readonly token: string;
private tokenStream: Subject<string>;
public isLoggedIn(): Observable<boolean> {
if (!this.tokenStream) {
this.tokenStream = new BehaviorSubject(this.token);
this.storage.observe(AuthService.JWT_TOKEN_KEY)
.subscribe(token => this.tokenStream.next(token));
}
return this.tokenStream.map(token => {
return token != null
});
}
verwendet ngx-webstorage
. und RxJS BehaviorSubject
.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Herausforderungen des AuthService mit RxJs
Dies war eines der Dinge, die ich kämpfte, als Wechsel von AngularJs ist, verspricht Winkel die Beobachtbaren Muster. Sehen Sie verspricht, werden pull-Benachrichtigungen und observablen sind push-Benachrichtigungen. Als solche müssen Sie überdenken Ihre AuthService, so dass es verwendet eine push-Muster. Ich dachte in Bezug auf sich ziehen, auch wenn ich schrieb, die Arbeit Observablen. Ich konnte nicht aufhören zu denken in Bezug auf sich ziehen.
Mit einem Versprechen-Muster war es einfacher. Wenn die AuthService erstellt wurde, wäre es entweder ein Versprechen, das aufgelöst wird, auf "nicht angemeldet" oder es wäre ein async Versprechen, dass würde die "Wiederherstellung protokolliert Staat". Sie könnte dann eine Methode namens
isLoggedIn()
zurückgeben würde, die Versprechen. Das erlaubt Ihnen, leicht zu handhaben Verzögerungen zwischen der Anzeige von Benutzer-Daten und Sie erhalten die Benutzerdaten.AuthService als Push-Dienst
Nun, schalten wir auf die Observablen und die verb "ist" muss geändert werden, "wenn". Machen diese kleine änderung hilft Sie re-denken, wie die Dinge sind zu arbeiten. So ermöglicht das umbenennen "isLoggedIn" zu "whenLoggedIn ()", die eine Beobachtbare, dass sendet Daten, wenn ein Benutzer authentifiziert.
Wenn ein Benutzer übergeben
setUser
es emittiert, um abonniert, dass ein neuer Benutzer authentifiziert wurde.Probleme Mit Dem Obigen Ansatz
Oben bringt einige Probleme, die behoben werden müssen.
whenLoggedIn
hören wird für neue Nutzer für immer. Die ziehen Strom ist nie abgeschlossen.setUser
verloren, nachdem Sie geschoben, an die Abonnenten.Können wir beheben einige dieser durch den Wechsel von
Subject
zuBehaviorSubject
.Dies ist sehr viel näher an dem, was wir wollen.
Änderungen
BehaviorSubject
immer wieder den letzten Wert für jeden neue Abonnement.whenLoggedIn().first()
wurde Hinzugefügt abonnieren und auto Abmelden, nachdem der erste Wert empfangen wird. Wenn wir nichtBehaviorSubject
dies würde block, bis jemand riefsetUser
die vielleicht nie passieren.Probleme Mit BehaviorSubject
BehaviorSubject
funktioniert nicht für AuthService und ich werde zeigen, mit diesem Beispiel-code hier.Hier ist, wie würde das problem in deinem code.
Oben erstellt eine neue AuthService mit einem token zur Wiederherstellung der Benutzer-session, aber wenn es läuft die Konsole einfach druckt "null".
Dies geschieht, weil
BehaviorSubject
erstellt wird, mit einem anfänglichen Wert vonnull
, und der Vorgang zur Wiederherstellung der Benutzer-Sitzung passieren wird später, nach der HTTP-Aufruf abgeschlossen ist. AuthService weiterhin emittierennull
bis die Sitzung wieder hergestellt, aber das ist ein problem, wenn Sie wollen, verwenden Sie route Aktivatoren.ReplaySubject Ist Besser
Wollen wir daran erinnern, den aktuellen Benutzer, aber nicht emittieren etwas, bis wir wissen, ob es ein user oder nicht.
ReplaySubject
ist die Antwort auf dieses problem.Hier ist, wie Sie es verwenden würden.
Die oben nicht warten, bis der erste Wert entsteht durch
whenLoggedIn
. Es wird diefirst
Wert-und Abmelden.ReplaySubject
funktioniert, weil es erinnert sich an die1
Elemente oder strahlt nichts. Es ist die nichts Teil, der wichtig ist. Wenn wir AuthService incanActivate
wir wollen warten, bis ein Benutzer Zustand ist bekannt.CanActivate Beispiel
Diesem jetzt macht es viel einfacher zu schreiben, die ein Benutzer guard, leitet zu einer login-Bildschirm oder die Möglichkeit, die route zu ändern.
Dieser wird der Ertrag einer Beobachtbaren true oder false, wenn es ein Benutzer-session. Es wird auch block-router ändern, bis dieser Staat bekannt ist (das heißt, sind wir abrufen der Daten vom server?).
Es wird auch umleiten, die router login-Bildschirm, wenn es keine user-Daten.
.first()
außerhalb des AuthService, und nur in derCanActivate
. Das ist, weil der Aktivator muss nur den aktuellen Zustand. Sie können Tiefgestellt zuwhenLoggedIn()
- und eben nicht Abmelden. Erhalten Sie user-Daten für die log-ins und null für die log-outs.canActivate
. Nach einem bisschen console logging, es scheint, dass die Winkel abmeldet aus dem Beobachtbaren einmal hat Sie es genannt. Das ist das problem 🙂 Wenn die Seite geladen wird, wirdcanActivate
aufgerufen wird => feines Benutzer nicht angemeldet, so zeigt die login-Komponente. Aber wenn Sie sich mit ErfolgcanActivate
ist nicht wieder angerufen, und da Winkel hat sich bei uns Abmelden, wird die Umleitung nicht passieren.ReplaceSubject
up, ich didn ' T wissen über Sie und ich denke, es ist wirklich nützlich für den Fall, die Sie erwähnen !Dies ist, wie ich es gemacht
Dies ist in einer anderen situation, wo ich das Kennwort ändern:
Soweit ich sehe, sollten Sie versuchen, das hinzufügen einer return-Typ der map-Funktion war dies eine Sache, die mir Probleme. Wenn Sie nicht fügen Sie eine return-Typ der map-Funktion, die in diesem Kontext funktioniert es nicht.
So einfach tun .anzeigen((): boolean => {} ...)