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],
}
Есть ли недостатки у такого подхода?