Angular’s route guards are interfaces which can tell the router whether or not it should allow navigation to a requested route. They make this decision by looking for a true or false return value from a class which implements the given guard interface.
There are five different types of guards and each of them is called in a particular sequence. The router’s behavior is modified differently depending on which guard is used. The guards are:
CanActivate
CanActivateChild
CanDeactivate
CanLoad
Resolve
The service injects AuthService and Router and has a single method called canActivate. This method is necessary to properly implement the CanActivate interface.
The canActivate method returns a boolean indicating whether or not navigation to a route should be allowed. If the user isn’t authenticated, they are re-routed to some other place, in this case a route called /login.
Our guard:
import { Injectable } from "@angular/core";
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from "@angular/router";
import { select, Store } from "@ngrx/store";
import { Observable } from "rxjs";
import { tap } from "rxjs/internal/operators/tap";
import { AppState } from "../reducers";
import { isLoggedIn } from "./auth.selectots";
@Injectable()
export class AuthGuard implements CanActivate {
constructor(
private store: Store<AppState>,
private route: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
return this.store.pipe(
select(isLoggedIn),
tap(isLogged => {
if (!isLogged) {
this.route.navigateByUrl('/login')
}
})
)
}
}
Then we should need to inject our guard in our module.ts providers:
import { ModuleWithProviders, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { LoginComponent } from './login/login.component';
import { MatCardModule } from "@angular/material/card";
import { MatInputModule } from "@angular/material/input";
import { RouterModule } from "@angular/router";
import { ReactiveFormsModule } from "@angular/forms";
import { MatButtonModule } from "@angular/material/button";
import { StoreModule } from '@ngrx/store';
import { AuthService } from "./auth.service";
import { authReducer } from './reducers';
import { AuthGuard } from './auth.guard';
@NgModule({
imports: [
CommonModule,
ReactiveFormsModule,
MatCardModule,
MatInputModule,
MatButtonModule,
RouterModule.forChild([{ path: '', component: LoginComponent }]),
StoreModule.forFeature('auth', authReducer)
],
declarations: [LoginComponent],
exports: [LoginComponent]
})
export class AuthModule {
static forRoot(): ModuleWithProviders<AuthModule> {
return {
ngModule: AuthModule,
providers: [
AuthService,
AuthGuard // HERE
]
}
}
}
And finally, we need to add our guard in our routes:
const routes: Routes = [
{
path: 'courses',
loadChildren: () => import('./courses/courses.module').then(m => m.CoursesModule),
canActivate: [AuthGuard] // This is an array because we can add multiple guards
},
{
path: '**',
redirectTo: '/'
}
];