Как использовать Guards (CanActivate, CanDeactivate)?
В Angular Guards — это специальные сервисы, реализующие интерфейсы CanActivate, CanDeactivate, CanLoad, CanActivateChild, Resolve, которые позволяют управлять доступом к маршрутам, отклонять переходы, предзагружать данные или подтверждать выход со страницы. Guards выступают как "стражи маршрутов", и работают до того, как Angular активирует маршрут.
CanActivate
Назначение
Проверяет, можно ли активировать (перейти к) определённому маршруту. Часто используется для защиты маршрутов от неавторизованных пользователей.
Интерфейс
interface CanActivate {
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean;
}
Пример реализации
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.authService.isLoggedIn()) {
return true;
}
this.router.navigate(\['/login'\]);
return false;
}
}
Применение в маршрутах
{
path: 'dashboard',
component: DashboardComponent,
canActivate: \[AuthGuard\]
}
CanDeactivate
Назначение
Контролирует возможность покинуть маршрут. Например, используется для предупреждения при незаполненной форме или несохранённых данных.
Интерфейс
interface CanDeactivate<T> {
canDeactivate(
component: T,
currentRoute: ActivatedRouteSnapshot,
currentState: RouterStateSnapshot,
nextState?: RouterStateSnapshot
): Observable<boolean> | Promise<boolean> | boolean;
}
Пример интерфейса компонента
export interface CanComponentDeactivate {
canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}
Пример компонента
@Component({...})
export class EditProfileComponent implements CanComponentDeactivate {
hasUnsavedChanges = true;
canDeactivate(): boolean {
return !this.hasUnsavedChanges || confirm('У вас есть несохранённые изменения. Покинуть страницу?');
}
}
Пример CanDeactivate guard
@Injectable({ providedIn: 'root' })
export class ConfirmExitGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(component: CanComponentDeactivate): boolean {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
Применение в маршрутах
{
path: 'edit',
component: EditProfileComponent,
canDeactivate: \[ConfirmExitGuard\]
}
Совместное использование CanActivate и CanDeactivate
{
path: 'editor',
component: EditorComponent,
canActivate: \[AuthGuard\],
canDeactivate: \[ConfirmExitGuard\]
}
CanActivateChild
Назначение
Ограничивает доступ к дочерним маршрутам.
Пример
@Injectable({ providedIn: 'root' })
export class ChildGuard implements CanActivateChild {
constructor(private authService: AuthService) {}
canActivateChild(): boolean {
return this.authService.hasChildAccess();
}
}
Применение
{
path: 'admin',
component: AdminComponent,
canActivateChild: \[ChildGuard\],
children: \[
{ path: 'users', component: UsersComponent },
{ path: 'roles', component: RolesComponent }
\]
}
CanLoad
Назначение
Предотвращает загрузку ленивого модуля, если условие не выполнено. Это важно, чтобы вообще не загружать код недоступных разделов.
Пример
@Injectable({ providedIn: 'root' })
export class AuthLoadGuard implements CanLoad {
constructor(private authService: AuthService) {}
canLoad(): boolean {
return this.authService.isAdmin();
}
}
Применение
{
path: 'admin',
loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule),
canLoad: \[AuthLoadGuard\]
}
В отличие от CanActivate, CanLoad блокирует саму загрузку JS-чанка, а не только отображение компонента.
Возврат значений
Guards могут возвращать:
-
true — разрешить переход.
-
false — отклонить переход.
-
UrlTree — перенаправить.
Пример с UrlTree
canActivate(): UrlTree {
return this.router.createUrlTree(\['/access-denied'\]);
}
Асинхронные Guards
Guards могут быть async:
canActivate(): Observable<boolean> {
return this.authService.checkSession(); // HTTP или локальный storage
}
Поддерживаются Promise, Observable, а также combineLatest, switchMap и другие RxJS-операторы.
Общая структура
@NgModule({
imports: \[RouterModule.forRoot(\[
{
path: 'secure',
component: SecureComponent,
canActivate: \[AuthGuard\],
canDeactivate: \[ConfirmExitGuard\],
canActivateChild: \[ChildGuard\],
canLoad: \[AuthLoadGuard\]
}
\])\],
exports: \[RouterModule\]
})
export class AppRoutingModule {}
Проверка очередности
При маршрутизации Angular вызывает guards в следующем порядке:
-
canLoad (для ленивых модулей).
-
canActivate / canActivateChild.
-
canDeactivate (при уходе с маршрута).
Guards позволяют централизованно управлять доступом, безопасностью, подтверждением действий и навигацией в Angular-приложениях, что критически важно для масштабируемых и безопасных архитектур.