Angular AuthGuard: CanActivate и CanActivateChild устарели. Как их заменить?

Мое приложение Angular включает в себя простой AuthGuard, как показано ниже, и с ним никогда не было проблем. Недавно я обновил свою версию Angular с 15.1.4 до 15.2.0, и с тех пор моя IDE показывает, что и то, и другоеCanActivateChildустарели.

Официальная документация Angular дляCanActivateговорит:

Устарело: вместо этого используйте простые функции JavaScript.

Как мне нужно настроить приведенный ниже код, чтобы избавиться от устаревшего предупреждения?

      export class AuthGuard implements CanActivate, CanActivateChild {

    constructor(private authService: AuthenticationService) {}

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree  {
        return this.authService.checkLogin()
            .pipe(
                map(() => true),
                catchError(() => {
                    this.router.navigate(['route-to-fallback-page']);
                    return of(false);
                }
            )
        );
    }

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

4 ответа

на основе: https://angular.io/guide/router#preventing-unauthorized-access

старый:

      @Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  constructor(private router: Router) {}

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean 
  {
    //your logic goes here
  }
}

новый:

      @Injectable({
  providedIn: 'root'
})
class PermissionsService {

  constructor(private router: Router) {}

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
      //your logic goes here
  }
}

export const AuthGuard: CanActivateFn = (next: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean => {
  return inject(PermissionsService).canActivate(next, state);
}

нет необходимости менять маршруты, и вы можете использовать их так же, как и раньше:

       {
    path: 'Dashboard',
    canActivate: [AuthGuard],
    component: DashboardComponent
  }

Как указано в официальном документе:

Защита маршрутов на основе классов устарела в пользу функциональной защиты. Внедряемый класс можно использовать в качестве функциональной защиты с помощью функции inject: canActivate: [() => inject(myGuard).canActivate()].

Это означает, что реализация метода canActivate через реализацию класса CanActivate в дочернем классе устарела. Вместо этого вам придется вызывать эту функцию непосредственно из файла модуля маршрутизации, где происходит объявление компонента.

      // Routing Module File.ts

// Example 1 ~ Without parameters

{
    path: 'Dashboard',
    canActivate: [() => inject(AuthGuard).canActivate()], // AuthGuard is your same class as it was before
    component: DashboardComponent 
}

// Example 2 ~ With parameters

{
    path: 'Dashboard',
    canActivate: [(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) => inject(AuthGuard).canActivate(next, state)],
    component: DashboardComponent
}

Надеюсь, это поможет вам или кому-то еще. Спасибо!

Приятного кодирования :-)

Как упоминалось в Angular Doc, здесь защита на основе классов устарела. Ссылка на документ.

Таким образом, чтобы преодолеть проблему CanActivate Deprecated, вам необходимо написать защиту маршрутов на основе функций, как указано в угловом документе. для этогоinject()может помочь вам внедрить зависимость, которую вы сделали вconstructorкласса охранника.

Преобразовал ваш код в функциональную защиту аутентификации:

       export const authGuard: CanActivateFn = (
   route: ActivatedRouteSnapshot,
   state: RouterStateSnapshot
 ): Observable<boolean | UrlTree | Promise<boolean | UrlTree | boolean | UrlTree = {

    
    // here injecting dependencies
    const authService = inject(AuthenticationService);
    const router = inject(Router);


    // here you existing implementation of canActivate
    return authService.checkLogin().pipe(
     map(() = true),
     catchError(() = {
       void router.navigate(['route-to-fallback-page']);
       return of(false);
     })
   );
 };

Кто-нибудь знает, в чем причина такого серьезного изменения в минорной версии?

У некоторых из нас внутри классов Guard много логики. У других много охранников. В таких случаях, чтобы сохранить разделение, я бы использовал следующий подход (используя методы статического класса):

      export namespace AuthGuard {
    export const canActivate = (
        route: ActivatedRouteSnapshot, 
        state: RouterStateSnapshot
    ) => {
        const authService = inject(AuthenticationService);
        const router = inject(Router);

        return authService.checkLogin().pipe(
                map(() => true),
                catchError(() => {
                    router.navigate(['route-to-fallback-page']);
                    return of(false);
                }
            )
        );
    }

    export const canActivateChild = (
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot
    ) => canActivate(route, state);
}

Затем в конфигурации вашего роутера:

      {
    ...
    canActivate: [AuthGuard.canActivate],
    canDeactivate: [AuthGuard.canDeactivate],
}

Есть ли недостатки у такого подхода?

Другие вопросы по тегам