Как защитить роуты с помощью guards (CanActivate)?angular-33

Guards в Angular - это механизм для контроля доступа к маршрутам. CanActivate - это интерфейс, который позволяет определить, может ли пользователь перейти по определенному маршруту.

Основные шаги реализации:

  1. Создание Guard: Сначала нужно создать класс, реализующий интерфейс CanActivate.
import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, 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(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {

    if (this.authService.isAuthenticated()) {
      return true;
    } else {
      // Перенаправляем на страницу входа
      return this.router.createUrlTree(['/login']);
    }
  }
}
  1. Регистрация Guard в модуле: Guard должен быть зарегистрирован как провайдер в Angular модуле.

  2. Применение Guard к роуту: В конфигурации маршрутов добавляем guard к нужным роутам.

const routes: Routes = [
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
  { path: 'profile', component: ProfileComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent }
];

Дополнительные возможности:

  • Передача данных в Guard: Можно передавать дополнительные данные через свойство data в конфигурации роута.
{
  path: 'admin',
  component: AdminComponent,
  canActivate: [AuthGuard],
  data: { roles: ['admin'] }
}

И затем использовать эти данные в Guard:

canActivate(
  next: ActivatedRouteSnapshot,
  state: RouterStateSnapshot): boolean {

  const requiredRoles = next.data.roles;
  // Проверка ролей пользователя
}
  • Асинхронные проверки: Метод canActivate может возвращать Observable или Promise для асинхронных операций.
canActivate(): Observable<boolean> {
  return this.authService.checkAuth().pipe(
    map(isAuth => isAuth || this.router.parseUrl('/login'))
  );
}

Лучшие практики:

  1. Всегда возвращайте UrlTree для перенаправлений (новый подход Angular)
  2. Разделяйте guards по ответственностям (авторизация, проверка ролей и т.д.)
  3. Используйте canActivateChild для защиты дочерних роутов
  4. Тестируйте guards изолированно

Пример комплексного Guard:

@Injectable()
export class RoleGuard implements CanActivate {
  constructor(private auth: AuthService, private router: Router) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean|UrlTree> {
    return this.auth.currentUser$.pipe(
      take(1),
      map(user => {
        const requiredRoles = route.data.roles;

        if (!user) {
          return this.router.createUrlTree(['/login'], {
            queryParams: { returnUrl: state.url }
          });
        }

        if (!requiredRoles || requiredRoles.some(role => user.roles.includes(role))) {
          return true;
        }

        return this.router.createUrlTree(['/access-denied']);
      })
    );
  }
}

Резюмируем

Guards - мощный механизм защиты маршрутов в Angular. Они позволяют гибко управлять доступом, интегрироваться с сервисами аутентификации и реализовывать сложные сценарии проверки прав доступа. Правильное использование guards значительно повышает безопасность Angular-приложений.