Prevent Access to Pages in Ionic with Angular Route Guards
In this tutorial, we are going to cover how to use route guards with Angular routing to prevent access to certain routes if certain conditions have not been met. A common example of this is preventing access to certain pages if the user is not logged in, and that is what we will be focusing on.
Outline
Angular Route Guards
The basic idea behind a route guard is that you attach a service which acts as the "route guard" to a particular route. That service has a canActivate
method which will return either true
or false
depending on whether the user should be allowed to go to that route or not. If the canActivate
method returns false, then the user will not be able to access the route.
Route guards make the process of protecting certain routes and redirecting the user quite simple, and in my opinion, more manageable than using navigation guards like ionViewCanEnter
on individual components. The end result looks something like this:
const routes: Routes = [
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: 'login', loadChildren: './login/login.module#LoginPageModule' },
{
path: 'home',
loadChildren: './home/home.module#HomePageModule',
canActivate: [AuthGuardService],
},
];
All we need to do is add one additional property to the route definitions to determine if the route can be activated. Since the routes in the example above are lazy loaded, we could also use canLoad
instead of canActivate
to entirely prevent the loading of the children for that route (rather than just preventing access).
It is important to note that most things we implement on the client side (i.e. not on a server) are more for user experience than security. Client-side code is accessible/modifiable by the user, so you should never use route guards to protect information that you don't want the user to see (just as you shouldn't solely use client-side code to validate/sanitise user entered data). Think of your route guards as a friendly security guard directing traffic – they can keep people away from where they are not supposed to be, and direct them to where they need to go, but anybody with malicious intent could easily run right by the guard. Anything in your application that needs to be kept secure should only be accessible through a server that your application communicates with.
Creating a Route Guard
Creating a route guard is as simple as creating a service that implements a canActivate
method. For example, we could generate an AuthGuard
service with the following command:
ionic g service services/AuthGuard
Then, all you need to do is have this canActivate
method return true
or false
and you can do whatever you like to determine that value:
import { Injectable } from '@angular/core';
import { Router, CanActivate, ActivatedRouteSnapshot } from '@angular/router';
@Injectable({
providedIn: 'root',
})
export class AuthGuardService implements CanActivate {
constructor(private router: Router) {}
canActivate(route: ActivatedRouteSnapshot): boolean {
console.log(route);
let authInfo = {
authenticated: false,
};
if (!authInfo.authenticated) {
this.router.navigate(['login']);
return false;
}
return true;
}
}
In this example, we have just set up a dummy object called authInfo
that has an authenticated
value of false. In a real-life situation, we would just pull this authenticaiton information from whatever is responsible for authenticating the user. We then check that value, and it the user is not authenticated we send them back to the login page and return false
– otherwise, we just return true
which will allow the navigation to proceed.
Although we are not using it, we have also injected ActivatedRouteSnapshot
which will allow you to access details about the route that the user is navigating to. You may need details about the route, like the parameters that were supplied, in order to determine whether or not to allow a user to proceed.
Attach the Route Guard to your Routes
All that is left to do once you create the route guard is to import it into the file that contains your routes, and attach it to any routes you want to protect with it:
import { NgModule } from '@angular/core';
import { PreloadAllModules, RouterModule, Routes } from '@angular/router';
import { AuthGuardService } from './services/auth-guard.service';
const routes: Routes = [
{ path: '', redirectTo: '/login', pathMatch: 'full' },
{ path: 'login', loadChildren: './login/login.module#LoginPageModule' },
{
path: 'home',
loadChildren: './home/home.module#HomePageModule',
canActivate: [AuthGuardService],
},
];
@NgModule({
imports: [
RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }),
],
exports: [RouterModule],
})
export class AppRoutingModule {}
You can use multiple different route guards if you like, and you can attach the same route guard to multiple different routes.
Summary
The approach that Angular routing uses for route/navigation guards is quite similar in the end to the way you would have done it with ionViewCanEnter
– ultimately, it is just a function returning true
or false
. However, I think the benefit of this approach is that it is a little more organised and it is easier to apply guards to multiple routes.