В Angular механизм защиты маршрутов используется для управления доступом к определенным частям приложения. Этот механизм позволяет определять, какие маршруты доступны пользователю в зависимости от различных условий, таких как аутентификация, авторизация или другие бизнес-правила. Защищенные маршруты (Guards) являются основным инструментом для реализации такого контроля.
Angular предоставляет несколько типов Guards, которые можно применить к маршрутам, для реализации различных сценариев доступа:
Каждый из этих типов Guard выполняет свою задачу, определяя логику доступа в соответствующий момент жизненного цикла маршрута.
Для создания Guard-а в Angular используется сервис, который реализует
один или несколько интерфейсов. Рассмотрим пример реализации
CanActivate Guard-а.
Для создания Guard-а используется Angular CLI:
ng generate guard auth
Это создаст сервис, реализующий интерфейсы CanActivate и
другие, если они указаны при генерации. Пример реализации
CanActivate Guard-а:
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
if (this.authService.isAuthenticated()) {
return true;
} else {
this.router.navigate(['/login']);
return false;
}
}
}
В данном примере Guard проверяет, авторизован ли пользователь, с
помощью метода isAuthenticated() из сервиса
AuthService. Если пользователь не авторизован, его
перенаправляют на страницу входа.
После реализации Guard-а его необходимо применить к маршруту. Для
этого в конфигурации маршрутов указывается свойство
canActivate, которое принимает массив с одним или
несколькими Guard-ами.
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './auth.guard';
import { DashboardComponent } from './dashboard/dashboard.component';
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
canActivate: [AuthGuard]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Теперь маршрут /dashboard будет доступен только в
случае, если AuthGuard вернет true.
Этот Guard используется для защиты дочерних маршрутов от
несанкционированного доступа. Он применяется аналогично
CanActivate, но работает на уровне дочерних маршрутов.
Пример:
const routes: Routes = [
{
path: 'parent',
component: ParentComponent,
canActivateChild: [AuthGuard],
children: [
{
path: 'child',
component: ChildComponent
}
]
}
];
В этом примере для всех дочерних маршрутов компонента
ParentComponent будет проверяться доступность через
AuthGuard.
Этот Guard проверяет, можно ли покинуть текущую страницу, например, если пользователь заполнил форму, но не сохранил данные. Он позволяет предупредить о потере данных.
Пример реализации:
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs';
export interface CanComponentDeactivate {
canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}
@Injectable({
providedIn: 'root'
})
export class UnsavedChangesGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(
component: CanComponentDeactivate
): Observable<boolean> | Promise<boolean> | boolean {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
Использование Guard-а в маршрутах:
const routes: Routes = [
{
path: 'form',
component: FormComponent,
canDeactivate: [UnsavedChangesGuard]
}
];
Этот Guard предотвращает загрузку модуля, если пользователь не авторизован. Он полезен для разделения больших приложений на модули и контроля доступа на уровне загрузки этих модулей.
Пример:
const routes: Routes = [
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
canLoad: [AuthGuard]
}
];
В данном случае, если Guard возвращает false, модуль
AdminModule не будет загружен.
Этот Guard используется для предварительной загрузки данных перед тем, как маршрут будет активирован. Это особенно полезно, если необходимо подгрузить данные для компонента перед его рендером.
Пример:
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Observable } from 'rxjs';
import { DataService } from './data.service';
@Injectable({
providedIn: 'root'
})
export class DataResolver implements Resolve<any> {
constructor(private dataService: DataService) {}
resolve(): Observable<any> {
return this.dataService.getData();
}
}
Использование Resolve в маршрутах:
const routes: Routes = [
{
path: 'dashboard',
component: DashboardComponent,
resolve: {
data: DataResolver
}
}
];
Теперь, перед активацией маршрута /dashboard, данные
будут загружены и переданы в компонент.
Angular выполняет Guard-ы в следующем порядке:
CanLoad (если применяется к модулю).CanActivate для самого маршрута.CanActivateChild для дочерних маршрутов.CanDeactivate перед покиданием маршрута.Resolve для загрузки данных перед активацией
маршрута.Понимание этого порядка позволяет точно настраивать маршруты и контролировать доступ в зависимости от логики приложения.
CanDeactivate можно предотвращать потерю данных при уходе с
страницы.CanLoad
можно предотвратить загрузку ресурсов для недоступных маршрутов.Resolve позволяет загрузить необходимые данные до активации
маршрута, предотвращая проблемы с асинхронностью.Использование Guards в Angular значительно улучшает безопасность и управляемость приложениями, позволяя точно настроить поведение маршрутов и контролировать доступ.