I am trying to create a service that authenticates a user and stores the token in the localStorage. I want other services (specifically the auth guard) to be able to access the current user, so I have set up the constructor of the authentication service like this:
currentUserSubject: BehaviorSubject<Token>;
constructor(private http: HttpClient) {
this.currentUserSubject = new BehaviorSubject<Token>(JSON.parse(localStorage.getItem('currentUser')));
}
When a user logs in using a http POST request, if it's successful call the next
method on the currentSubject
like this:
return this.http.post<Token>(`${environment.identityServerUrl}/connect/token`, params, httpOptions)
.pipe(map(user => {
localStorage.setItem('currentUser', JSON.stringify(user));
console.log(user);
this.currentUserSubject.next(user);
}));
The problem is, it doesn't seem to work. If I check my auth guard, it just sees the user as null. Only when I refresh is it populated (because of the authentication service constructor).
My auth guard looks like this:
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { mapTo, take, filter } from 'rxjs/operators';
import { AuthenticationService } from './authentication.service';
@Injectable({ providedIn: 'root' })
export class AuthGuardService implements CanActivate {
constructor(
private router: Router,
private authenticationService: AuthenticationService
) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.authenticationService.currentUserSubject.pipe(
filter(user => !!user),
mapTo(true),
take(1)
);
}
}
Does anyone know what I am doing wrong?
If I change my canActivate
method to this:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean|UrlTree {
var user = this.authenticationService.currentUserSubject.value;
console.log(user);
if (user) return true;
this.router.navigate(["login"],{ queryParams: { retUrl: route.url} });
return false;
}
It should work, but it just the console log shows null
and so it just stays on the login page.
I saw that you can get .value
from this article:
https://medium.com/@luukgruijs/understanding-rxjs-behaviorsubject-replaysubject-and-asyncsubject-8cc061f1cfc0
/connect/token
and anything consuming it will receivenull
. – Alexander Staroselsky