MST

星途 面试题库

面试题:Angular路由守卫在复杂业务场景下的深度应用及优化

假设你正在开发一个多角色权限管理的复杂系统,不同角色对某些路由页面具有不同的访问权限。请详细描述如何利用Angular的路由守卫(CanActivate、CanDeactivate等)来实现该功能,并说明在大量路由和复杂权限规则下,如何对路由守卫进行优化以提升性能。
13.3万 热度难度
前端开发Angular

知识考点

AI 面试

面试题答案

一键面试

利用Angular路由守卫实现多角色权限管理

  1. CanActivate守卫实现访问权限控制
    • 创建守卫类
      • 首先创建一个实现CanActivate接口的守卫类,例如AuthGuard
      • 在类中注入必要的服务,如用于获取用户角色和权限信息的AuthService
      import { Injectable } from '@angular/core';
      import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
      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
        ): boolean | Promise<boolean> | Observable<boolean> {
          const userRole = this.authService.getUserRole();
          const routePermissions = next.data['permissions'];
      
          if (routePermissions.includes(userRole)) {
            return true;
          } else {
            this.router.navigate(['/forbidden']);
            return false;
          }
        }
      }
      
    • 配置路由
      • app - routing.module.ts中,为需要权限控制的路由配置canActivate属性。
      const routes: Routes = [
        {
          path: 'admin - dashboard',
          component: AdminDashboardComponent,
          canActivate: [AuthGuard],
          data: { permissions: ['admin'] }
        },
        {
          path: 'user - dashboard',
          component: UserDashboardComponent,
          canActivate: [AuthGuard],
          data: { permissions: ['user', 'admin'] }
        }
      ];
      
  2. CanDeactivate守卫实现离开页面权限控制(可选,根据业务需求)
    • 创建守卫类
      • 创建实现CanDeactivate接口的守卫类,例如LeaveGuard。同样注入必要服务。
      import { Injectable } from '@angular/core';
      import { CanDeactivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
      import { SomeComponent } from './some.component';
      
      @Injectable({
        providedIn: 'root'
      })
      export class LeaveGuard implements CanDeactivate<SomeComponent> {
        canDeactivate(
          component: SomeComponent,
          currentRoute: ActivatedRouteSnapshot,
          currentState: RouterStateSnapshot,
          nextState?: RouterStateSnapshot
        ): boolean | Observable<boolean> | Promise<boolean> {
          // 检查用户角色和当前页面离开权限规则
          const userRole = this.authService.getUserRole();
          if (component.canLeave(userRole)) {
            return true;
          } else {
            return confirm('You do not have permission to leave this page.');
          }
        }
      }
      
    • 配置路由
      • app - routing.module.ts中,为需要离开权限控制的路由配置canDeactivate属性。
      const routes: Routes = [
        {
          path:'sensitive - page',
          component: SensitivePageComponent,
          canDeactivate: [LeaveGuard]
        }
      ];
      

大量路由和复杂权限规则下的优化

  1. 缓存权限数据
    • AuthService中,缓存用户的权限信息。例如,在用户登录成功后,将用户角色和对应的权限列表缓存起来。
    • 每次CanActivate守卫检查权限时,优先从缓存中获取权限数据,而不是重复从后端获取,减少网络请求次数。
  2. 减少守卫逻辑复杂度
    • 将复杂的权限判断逻辑提取到独立的服务方法中,使得CanActivate守卫的canActivate方法保持简洁。例如,将权限匹配逻辑封装到AuthServicehasPermission方法中。
    • 这样,当权限规则发生变化时,只需要修改hasPermission方法,而不需要修改多个守卫的逻辑。
  3. 延迟加载路由和守卫
    • 对于不常用的路由模块,使用Angular的延迟加载功能。这样,只有在用户实际访问相关路由时,才会加载对应的模块及其守卫。
    • 在路由配置中,通过loadChildren属性实现延迟加载。
    const routes: Routes = [
      {
        path: 'rare - page',
        loadChildren: () => import('./rare - page.module').then(m => m.RarePageModule),
        canActivate: [AuthGuard]
      }
    ];
    
  4. 使用共享守卫实例
    • 在应用中,尽量使用同一个守卫实例来处理权限检查,避免每次路由变化都创建新的守卫实例。Angular的依赖注入系统默认会为每个注入点提供单例实例,确保守卫实例的一致性。
  5. 基于角色的权限分组
    • 对大量路由进行基于角色的权限分组。例如,将所有管理员权限的路由放在一个模块中,所有普通用户权限的路由放在另一个模块中。这样,在权限检查时,可以快速定位到对应的权限范围,减少检查的复杂度。