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);
}
CodePudding user response:
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;
}
})
)
}
CodePudding user response:
The is issue is very obviously. You did not return anything in your function.
Solution:
- add return to your function
canActivate
- 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;
}
});
}
}