I had a similar issue, and solved it using a authentication service, where I instead uses a BehaviorSubject, to track the member authentication state:
public member: Subject<Member> = new Subject<Member>();
private _cachedMember: Member;
private _member$: BehaviorSubject<Member>;
constructor(private _http: Http, private _router: Router) {
}
get member$(): Observable<Member> {
if (!this._cachedMember) {
this.getAuthorizedMember().subscribe();
}
return this._member$.asObservable();
}
private getAuthorizedMember(): Observable<Member> {
// call your auth API and set _cachedMember accordingly:
this._cachedMember = member;
this._member$.next(this._cachedMember);
}
My auth.guard.ts canActivate implementation:
canActivate(): Observable<boolean> | boolean {
return this._authService.member$.map(member => {
if (member) return true;
else {
// Set entry url
var currentUrl: URL = new URL(this._document.location.href);
this._authService.entryUrl = currentUrl.pathname;
this._router.navigate(['/']);
return false;
}
});
}
The else statement saves the url request, so the member is redirected correctly after login.
Then you only need to call your authentication API if the _cachedMember is null. Remember to set _cachedMember to null on logout and inform subjects.
logout() {
this._cachedMember = null;
this._member$.next(this._cachedMember );
}
[EDIT]
I found an issue with the earlier solution. Its a good idea to wrap the authorizing mechanism in an observable, and do a null check if the _member$ subject is assign. Then the initial state is valid if navigating directly to a route which is guarded!