Angular 的“CanActivate”接口已弃用。如何更换?

kel*_*mat 74 canactivate angular auth-guard canactivatechild candeactivate

我的 Angular 应用程序包含一个简单的应用程序,AuthGuard如下所示,并且从未出现过问题。最近,我将 Angular 版本从 15.1.4 升级到 15.2.0,从那时起,我的 IDE 表明 和CanActivate均已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);
    }
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*ler 82

诀窍是依赖于inject()您需要的实例的注入:

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

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

export const canActivateChild: CanActivateChildFn = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => canActivate(route, state);
Run Code Online (Sandbox Code Playgroud)

inject()允许您在注入上下文中使用依赖注入。例如,在构造函数中或类似此处将函数传递给核心 Angular 功能时。

您还可以在折旧清单上阅读相关信息。

另外,从 v16 开始,Angular 提供了一些辅助函数来将类转换为功能性守卫,例如mapToCanActivate

@Injectable({providedIn: 'root'})
export class AdminGuard {
  canActivate() {
    return true;
  }
}

const route: Route = {
  path: 'admin',
  canActivate: mapToCanActivate([AdminGuard]),
};
Run Code Online (Sandbox Code Playgroud)

您可以在这里找到其他人。

  • 我是该框架的谦虚贡献者,并密切关注 Angular 团队的工作。我可能会向 https://angular.io/guide/deprecations 提交一些更改以包含此主题。您不会是最后一个提出这个问题的人! (4认同)
  • 实际上 https://angular.io/guide/deprecations#router-class-and-injectiontoken-guards-and-resolvers 已经有一个很好的文档了!:) (3认同)
  • 是否存在应放置此类函数的约定(我的意思是,以便其他 Angular 开发人员本能地知道在哪里寻找它)? (2认同)
  • 我发布了对此弃用的解决方案。谁能解释一下,为什么要改变这个? (2认同)

ali*_*mat 52

基于: 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
  }
}
Run Code Online (Sandbox Code Playgroud)

新的:

@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);
}
Run Code Online (Sandbox Code Playgroud)

无需更改您的路线,可以像旧的一样使用它:

 {
    path: 'Dashboard',
    canActivate: [AuthGuard],
    component: DashboardComponent
  }
Run Code Online (Sandbox Code Playgroud)

  • 新方法在 16.2 版本中有效。我必须导入“CanActivateFn”和“inject”。例如:`从'@angular/core'导入{Injectable,inject};从 '@angular/router' 导入 { Router, ActivatedRouteSnapshot, RouterStateSnapshot, CanActivateFn };` (2认同)

Ama*_*pta 10

正如官方文档中所述:

基于类的路由防护已被弃用,取而代之的是功能防护。可注入类可以使用注入函数用作功能防护:canActivate: [() =>ject(myGuard).canActivate()]。

这意味着通过子类中的implements 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
}
Run Code Online (Sandbox Code Playgroud)

希望这会对您或其他人有所帮助。谢谢!

快乐编码:-)