Reputation: 427
My goal is to implement an AuthGuard that checks if a user has access to a specific route based on their role and the requested route and allow them to proceed if they have the right role for the route, or redirect them elsewhere if they do not.
The AuthGuard calls my AuthorizationService which returns an Observable(UserRole). I am having difficulty evaluating the user's observable and returning a value to canActivate. It is certainly related to my inexperience with RxJS Observables but I cannot seem to get past this one.
I have auth.guard.service.ts
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
let url: string = state.url;
var currentUser$ = this.authService.getCurrentUser();
currentUser$.subscribe((currentUser: MyUser) => {
if (currentUser.isInternalUser && url === '/internal') {
console.debug("Internal User! Yes");
this.router.navigate(['/internal']);
return true;
} else if (currentUser.isExternalUser && url === '/dashboard') {
console.debug("External User! Yes");
this.router.navigate(['/external']);
return true;
} else {
console.debug("Access Denied...");
this.router.navigate(['/pagenotfound']);
return false;
}
});
//return Observable.of(false); // I need to return something, but this is not what I want to return!!
}
auth.service.ts
getCurrentUser() : Observable<MyUser> {
let currentUser$: Observable<MyUser>;
currentUser$ = this.http.get(this.location.prepareExternalUrl('api/v1/userprofile/'))
.cache()
.map(this.extractData)
.catch(this.handleError);
console.log("AuthService#getCurrentUser being called.");
return currentUser$;
}
How can I evaluate my currentUser and have canActivate return a boolean observable?
Upvotes: 1
Views: 2106
Reputation: 18663
You need to return the Observable
before you subscribe to it. Subscribing is a terminal operation that informs the Observable that it is now connected and that it can begin pushing events to the subscribers (represented by the handlers you pass to the subscribe function).
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot
): Observable<boolean> {
const url: string = state.url;
return this.authService.getCurrentUser()
.flatMap(({isInternalUser, isExternalUser}: MyUser) => {
if (isInternalUser && url === '/internal') {
return Observable.fromPromise(this.router.navigate(['/internal']))
.mapTo(true);
} else if (isExternalUser && url === '/dashboard') {
return Observable.fromPromise(this.router.navigate(['/external']))
.mapTo(true);
} else {
return Observable.fromPromise(this.router.navigate(['/pagenotfound']))
.mapTo(false);
}
});
}
The above is a naive refactoring of the code that you supplied. I am afraid I don't know enough about Angular2 to tell you if that is actually how you should be implementing an Auth Guard (though I will say it does seem a little odd to be redirecting in what is ostensibly just a check of whether that page is accessible).
Also on a side note, cache
is being removed from the final release of RxJS 5 so you may want to avoid using it if you plan to upgrade.
Upvotes: 3