简体   繁体   中英

Angular AuthGuard does not return UrlTree from inside subscription

I am trying to implement UrlTree to redirect user if guard fails. this.authService.isAuthenticated() returns observable.

The following does not work but it does console false .

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree {
  this.authService.isAuthenticated().subscribe(isAuthenticated => {
    if (isAuthenticated) {
      return true;
    } else {
      console.log(isAuthenticated);
      return this.router.createUrlTree(['auth/sign-in']);
    }
  });
  return false;
}

But the following works if I remove subscription:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree {
  return this.router.createUrlTree(['auth/sign-in']);
}

You cannot return from inside subscribe (in any case). Route guard can return a boolean or an observable of a boolean. So in your case you need to return an observable of boolean. Worth mentioning also, in your current code, since this is async, what you are currently returning is always false no matter the logged in status, why? It takes x amount of time to get the authenticated status, so false is returned every time, angular does not wait for the response, just moves on to the next code available, which is return false; in your current code.

So, as said, return an observable, ie use map instead of subscribe :

import { map, take } from 'rxjs/operators';

// ....

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
  return this.authService.isAuthenticated()
    .pipe(
      take(1),
      map(isAuthenticated => {
        if (isAuthenticated) {
          return true;
        }
        // no need for else, if above is truthy, further code is not executed
        this.router.createUrlTree(['auth/sign-in']);
        return false;
      })
    );
}

Didnt know u need to redirect user so use this functions:

canActivate(route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean> {

        return this.authService.isAuthenticated().pipe(
            take(1),
            map(user => !!user),
            tap(loggedIn => {
                if (!loggedIn) {
                    this.router.navigate(['/login'])
                }
            })
        );
    }

@AJT82 answer didn't work for me in Angular 8. Returning a UrlTree with parseUrl and return a true is the only way it works.

canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return this.authService.auth$.pipe(
      map((authState: AuthState) => {
        console.log('=========root guard=============');
        if (!authState.isLoggedIn) {
          return this.router.parseUrl('/auth/login');
        }

        if (state.url === '' || state.url === '/') {
          if (authState.accessGroups.includes(AccessGroup.ADMIN)) {
            return this.router.parseUrl('/post/list');
          }
          if (authState.accessGroups.includes(AccessGroup.REEF)) {
            return this.router.parseUrl('/reef');
          }
        }
        return true;
      })
    );

And I don't really understand why returning the UrlTree is not enough. If I do not return the true the Router will be blocked. Very strange.

Setting the UrlTree and then returning True didn't work either. Only returning the UrlTree and return true works for me.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM