I have a route with two canActivate
guards (AuthGuard
and RoleGuard
). The first (AuthGuard
) checks to see if the user is logged in and, if not, redirects to the login page. The second checks to see if the user has a role defined that is allowed to view the page and, if not, redirects to the un-authorized page.
canActivate: [ AuthGuard, RoleGuard ]
...
export class AuthGuard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
...
this.router.navigate(['/login']);
resolve(false);
}
export class RoleGuard implements CanActivate {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
...
this.router.navigate(['/unauthorized']);
resolve(false);
}
The problem is that when I access the route and I am not logged in I hit the AuthGuard
, which fails and tells the router to navigate to /login
. However, even though the AuthGuard
failed, the RoleGuard
runs anyway which then navigates to /unauthorized
.
In my opinion it is pointless to run the next guard if the first fails. Is there any way to enforce this behavior?
This is due to the fact you are returning a Promise<boolean>
instead of just a boolean
. If you were to just return a boolean it wouldn't check the RoleGuard
. I would guess this is either a bug in angular2
or an expected result of async requests.
You can however resolve this with your example by only using RoleGuard
for urls where a certain Role
is required, because I guess you need to be logged in to have a role. In that case you can change your RoleGuard
to this:
@Injectable()
export class RoleGuard implements CanActivate {
constructor(private _authGuard: AuthGuard) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
return this._authGuard.canActivate(route, state).then((auth: boolean) => {
if(!auth) {
return false;
}
//... your role guard check code goes here
});
}
}
Update
In the latest Angular version (currently v8.x) - Even if both Guard will return false
- they will still be both executed. (behavior was aligned between different return values)