-1

I have a route guard that checks if a user has access to a resource, before proceeding. After the subscription, I check if the user has access, and if not, redirect using parseUrl or return true.

@Injectable({ providedIn: 'root' })
export class PortfolioGuard implements CanActivate {
  constructor(private resourceAccessService: ResourceAccessService, private router: Router) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean | UrlTree {
    const id = +route.paramMap.get('id');
    // return this.resourceAccessService.checkUserAccessToPortfolio(id);
    this.resourceAccessService.checkUserAccessToPortfolio(id).subscribe((hasAccess) => {
      if (!hasAccess) {
        console.log('No access');
        return this.router.parseUrl('/');
      } else {
        console.log('access');
        return true;
      }
    });
  }
}

This works if I only return the check, but I also want it to redirect based on that check.

@Injectable({ providedIn: 'root' })
export class PortfolioGuard implements CanActivate {
  constructor(private resourceAccessService: ResourceAccessService, private router: Router) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    const id = +route.paramMap.get('id');
    return this.resourceAccessService.checkUserAccessToPortfolio(id);
  }
}

What am I missing in the first block of code, should I be resolving the subscription from the service...

checkUserAccessToPortfolio(id: number): Observable<boolean>  {
    const url = this.baseUrl + this.userResourceAccessUrl + '/' + + id + '/portfolio';
    return this.http.get<boolean>(url);
  }
Christian Phillips
  • 18,399
  • 8
  • 53
  • 82

2 Answers2

0

I would try to return the Observable in the function:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean | UrlTree {
  const id = +route.paramMap.get('id');
    
  return this.resourceAccessService.checkUserAccessToPortfolio(id).pipe(
    map(hasAccess => {
      if (!hasAccess) {
        console.log('No access');
        this.router.parseUrl('/');
        return false
      } else {
        console.log('access');
        return true;
      }
    })
  )
}
Tobias S.
  • 21,159
  • 4
  • 27
  • 45
0

The is issue is very obviously. You did not return anything in your function.

Solution:

  1. add return to your function canActivate
  2. remove subscribe and move all logic to map operator. Or you can use tap, switchMap operator. it depends on your context.

Instead of doing this:

@Injectable({ providedIn: 'root' })
export class PortfolioGuard implements CanActivate {
  constructor(private resourceAccessService: ResourceAccessService, private router: Router) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean | UrlTree {
    const id = +route.paramMap.get('id');
    // return this.resourceAccessService.checkUserAccessToPortfolio(id);
    this.resourceAccessService.checkUserAccessToPortfolio(id).subscribe((hasAccess) => {
      if (!hasAccess) {
        console.log('No access');
        return this.router.parseUrl('/');
      } else {
        console.log('access');
        return true;
      }
    });
  }
}

You can try using pipe and map operator.

@Injectable({ providedIn: 'root' })
export class PortfolioGuard implements CanActivate {
  constructor(private resourceAccessService: ResourceAccessService, private router: Router) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean | UrlTree {
    const id = +route.paramMap.get('id');
    return this.resourceAccessService.checkUserAccessToPortfolio(id).pipe( map( hasAccess => {
      if(!hasAccess) {
        console.log('No access');
        this.router.parseUrl('/');
        return false
      } else {
        console.log('access');
        return true;
      }
    });
  }
}

Hoang Subin
  • 6,610
  • 6
  • 37
  • 56
  • I'm getting *Argument of type 'Observable' is not assignable to parameter of type 'OperatorFunction'. Type 'Observable' provides no match for the signature '(source: Observable): Observable'* – Christian Phillips Oct 19 '21 at 17:58