Angular Role Authorization Using Route Guards


Authorization in Angular is pretty simple using route guards. Route guards in Angular are very useful and powerful tools. They can restrict access to certain parts of your application based on logic that you define. I'm going to show a quick demo of how to use a route guard to block routes based on whether the user has a given role.
Don't rely solely on route guards to protect sensitive data, be sure to always validate user authorization at your API as well.
Setup
Let's use the Angular CLI to create the guard for us. Here is the command to create a new route guard:
ng g guard security/guards/hasRole --implements=CanActivate
I put it in the folder security/guards just because I like to keep them organized under my security folder.
--implements tells the CLI to create it with the CanActivate function already implemented. Here is the output of the class:
export class HasRoleGuard implements CanActivate {
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot
):
| Observable<boolean | UrlTree>
| Promise<boolean | UrlTree>
| boolean
| UrlTree {
return true;
}
}
In your routing module, set up the routes you want to protect:
{
path: 'protected',
component: ProtectedComponent,
canActivate: [HasRoleGuard],
data: { role: 'Admin' }
}
The canActivate
property tells the router which guard or guards needs to be run before a route can be visited. This is an array so you can add multiple guards, and each guard has to return true before the route can be visited.
The data
property lets you pass in whatever data to that guard that you want. In this case, I'm passing in a string called role
. This will be the role the user has to have in order to visit this route.
Validating Data
Now that we are telling the guard what role it needs to check for, let's update the guard to grab that data and compare it to our user.
All we need to do is grab the data from the ActivatedRouteSnapshot
that is passed into the canActivate function and check it against our user. Here's the whole guard:
The ActivatedRouteSnapshot
is passed in as next, so next.data.role
will access the role object we passed into the data property in our router module.
authService
is a service that I inject in the constructor and use to get the currently logged in user. This will vary based on how your application is set up, but in this example the user has an array called roles that holds the name of all the roles they currently have. I check to see if the role in the passed data exists in our users role array. If it does, return true, which tells the angular router it's ok to proceed to the route.
If the user does not have the role, I use the router to create a url tree to redirect to the /unauthenticated route. The url tree is a new feature added in 7.1. You can learn about it from the Angular documentation.
You can also use the guard to run asynchronous code and return an observable or promise. This is helpful if you want to pass the logic off to an API.
Summary
This is a simple example of checking for a single role, but you could also pass any type of object in the data property of your route. In some of our enterprise apps we've had the need to check for a single role as we did in this example, as well as checking if a user has one of multiple roles, or has every role in a list. The guards are very flexible and a great tool for preventing users from getting to pages they shouldn't.