如何实现使用 CanMatchFn 和 CanActivateFn 的 Angular AuthGuard?(如何将类守卫转换为功能守卫)

Mic*_*ely 5 angular angular14 angular15

我有以下 Angular AuthGuard:

\n
@Injectable({\n    providedIn: \'root\',\n})\nexport class AuthGuard implements CanActivate, CanLoad {\n    constructor(private authService: AuthService, private router: Router) {}\n\n    canActivate(\n        next: ActivatedRouteSnapshot,\n        state: RouterStateSnapshot,\n    ): | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {\n        return this.isAuthenticated();\n    }\n\n    canLoad(\n        route: Route,\n        segments: UrlSegment[],\n    ): | boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {\n        return this.isAuthenticated();\n    }\n\n    isAuthenticated(): | boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {\n        return this.authService.isAuthenticated$.pipe(\n            take(1),\n            tap((isAuthenticated: boolean) => {\n                if (!isAuthenticated) {\n                    this.router.navigate([\'/account/login\']);\n                }\n            }),\n        );\n    }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n

我更新到 Angular 15:

\n
Angular CLI: 15.2.0\nNode: 16.19.1\nPackage Manager: npm 8.19.3\nOS: darwin x64\n\nAngular: 15.2.0\n\nPackage                         Version\n---------------------------------------------------------\n@angular-devkit/core            15.2.0\n@angular-devkit/schematics      15.2.0\n@schematics/angular             15.2.0\n
Run Code Online (Sandbox Code Playgroud)\n

现在我收到以下 TS 折旧说明:\n在此输入图像描述\n还有 CanLoad 接口的类似折旧消息:

\n
@deprecated \xe2\x80\x94 Use CanMatchFn instead\n\'CanLoad\' is deprecated.\n
Run Code Online (Sandbox Code Playgroud)\n

我试图寻找如何使用推荐的CanActivateFnCanMatchFn来实现我的 AuthGuard ,但我找不到一个好的资源来实现这一点,并且能够在用户未经身份验证时重定向到某个路由,如它所示上面旧的 CanActivate 和 CanLoad 实现:

\n
this.router.navigate([\'/account/login\']);\n
Run Code Online (Sandbox Code Playgroud)\n

如何正确实现使用新的CanMatchFn和的简单 Angular AuthGuard CanActivateFn

\n

Mat*_*ler 8

最简单的方法是使用inject(AuthGuard).canActivateas CanActivateFn

如果你想重构以删除类,它是类似的:

const isAuthenticated = (): | boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> => {
    const authService = inject(AuthService);
    const router = inject(Router);
    return authService.isAuthenticated$.pipe(
        take(1),
        tap((isAuthenticated: boolean) => {
            if (!isAuthenticated) {
                this.router.navigate(['/account/login']);
            }
        }),
    );
}

const canActivate:CanActivateFn = isAuthenticated;
const canMatch:CanMatchFn = isAuthenticated;
Run Code Online (Sandbox Code Playgroud)

对于折旧CanLoad只需传入canMatch: [canMatch]您的路由器即可。


编辑:为了将来的参考,此 PR添加了新的辅助函数,以允许从类防护平滑迁移到功能防护。

  • mapToCanActivate([MyClassGuard])
  • mapToCanActivateChild([MyClassGuard])
  • mapToCanMatch([MyClassGuard])

等等。这可能会出现在 15.3 或 16.0 中。