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 the data
property of Route
. For example, in your routes, you could do something like:
{
path: "someroute",
component: SomeComponent,
canActivate: [RoleRouteGuard],
data: {
requiredRoles: ["Role1", "Role2", "Role3"]
}
}
Using this, you could take one of your existing CanActivate
implementations, and make it more generic. You can access the requiredRoles
property from data
via the ActivatedRouteSnapshot
. e.g:
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
const requiredRoles = route.data.requiredRoles;
....
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-of Admin
or Manager
role, you could also extend this to have multiple data
properties. For example, you could have requiredRoles
and atLeastOneOfRoles
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With