Защита роутера

CanActivate

Angular позволяет перед выполнением роутинга выполнить произвольный синхронный или асинхронный код. Для реализации предусмотрен специальный интерфейс CanActivate, импортируемый из @angular/router.

В качестве примера реализуем фейковый класс аутентификации app\auth.service.ts, который возвращает объект Promise, для поддержки асинхронности:

export class AuthService {
loggedIn = false;

isAuthenticated() {
const promise = new Promise(
(resolve, reject) => {
setTimeout(
() => {
resolve(this.loggedIn);
},
800
);
}
);
return promise;
}

login() {
this.loggedIn = true;
}

logout() {
this.loggedIn = false;
}
}

Создадим класс на основе интерфейса CanActivate. Данный класс является фильтром для роутера. Он должен реализовать метод canActivate, который возвращает булевое значение, в зависимости от которого, будет применен или нет роутинг. app\auth-guard.service.ts:

import { 
CanActivate,
ActivatedRouteSnapshot,
RouterStateSnapshot,
Router
} from "@angular/router";
import { Observable } from "rxjs/Observable";
import { Injectable } from "@angular/core";
import { AuthService } from "./auth.service";

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {};

canActivate(route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.isAuthenticated()
.then(
(authenticated: boolean) => {
if (authenticated) {
return true;
} else {
this.router.navigate(['/']);
return false
}
}
);
}
}

Реализуем Routes с применением параметра canActivate, данный массив содержит все сервисы, которые необходимо выполнить перед срабатыванием роутера. Если хотя бы один из сервисов вернет false, то перехода не будет. app-routing.module.ts:

const appRoutes: Routes = [
//...
{path: 'servers', canActivate: [AuthGuard], component: ServersComponent, children: [
{path: ':id', component: ServerComponent},
{path: ':id/edit', component: EditServerComponent},
]},
//...
];

В app\app.module.ts нужно не забыть включить в провайдеры класс реализующий интерфейс CanActivate и непосредственно сервис, реализующий авторизацию для данного примера:

@NgModule({
//...
providers: [
//...
AuthService,
AuthGuard
],
//...
})

Защита дочерних роутов с помощью CanActivateChild

При использовании интерфейса CanActivate, блокируется родительский роут и его дочерние роуты. Для блокировки только дочерних роутов можно использовать интерфейс CanActivateChild, в котором нужно реализовать метод canActivateChild(), например:

canActivateChild(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean
{
return this.canActivate(route, state);
}

И прописать в роутах ключ canActivateChild:

const appRoutes: Routes = [
//...
{
path: 'servers',
canActivateChild: [AuthGuard],
component: ServersComponent,
children: [
{path: ':id', component: ServerComponent},
{path: ':id/edit', component: EditServerComponent},
]
},
//...
];
Источник – курс «Angular 5 the complete guide», Maximilian Schwarzmüller
Редактировать на GitHub