I'm working on securing the front-end of my Angular application using route guards. In working with them in the past and researching online, adding multiple guards to a route requires all of them to return true to allow access.
But what if I want just one to return true to allow access? (like || instead of &&)
For example, my route guards look for certain roles in the user's token:
@Injectable()
export class ActiveRoleGuard implements CanActivate {
constructor(private sessionService: SessionService, private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let token = this.sessionService.getToken();
if (!token) {
return false;
}
if (token.role.toLowerCase().indexOf("active") < 0) {
this.router.navigate(["/issue"]);
return false;
}
return true;
}
}
And
@Injectable()
export class AdminRoleGuard implements CanActivate {
constructor(private sessionService: SessionService, private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
let token = this.appSessionService.getToken();
if (!token) {
return false;
}
if (token.role.toLowerCase().indexOf("admin") < 0) {
this.router.navigate(["/issue"]);
return false;
}
return true;
}
}
If I was to combine them normally in a router module it would be something like...
{path: "someroute", component: SomeComponent, canActivate: [ActiveRouteGuard, AdminRouteGuard]}
... but that would require a user to be both Active
and an Admin
. But what if I wanted to enforce being Active
and either an Admin
or a Manager
?
It's simple to enforce on the API like so:
[Authorize(Roles = "Active")]
[Authorize(Roles = "Admin, Manager")]
public class SomeController : ApiController
but how do I do this in Angular?
Rather than having two separate
CanActivate
implementations, you could just use a single version that can be "configured". To do this, you can take advantage of thedata
property ofRoute
. For example, in your routes, you could do something like:Using this, you could take one of your existing
CanActivate
implementations, and make it more generic. You can access therequiredRoles
property fromdata
via theActivatedRouteSnapshot
. e.g:Once you've got this, you can check if the token's role is in the array, etc, etc.
If you have an always-required
Active
role and then a one-ofAdmin
orManager
role, you could also extend this to have multipledata
properties. For example, you could haverequiredRoles
andatLeastOneOfRoles
and update your logic to process that accordingly... There are many options at this point but I don't think you will need help with that.