2

我正在尝试创建一个基于角色的路由系统,其中app-routing模块有多个模块路由到同一路由。

例如。

const routes: CustomRoutes = [
  { path: 'login', component: LoginFormComponent },
  {
    path: '',
    canActivate: [CanActivateRole],
    data: {
      roles: UserType.ClientRoleType
    }, 
    pathMatch: 'full',
    loadChildren: () => { return ClientModule; },
  },
  {
    path: '',
    canActivate: [CanActivateRole],
    data: {
      roles: UserType.DCRoleType
    }, 
    pathMatch: 'full',
    loadChildren: () => { return DcEmpModule; },
  },
];

canActivateRole正在读取以route.data.roles确定它是否可以路由到loadChildren.

注意:我已尝试使用matcher配置路由以加载单独的模块,如 本答案中所示,但是由于我正在使用服务,所以我找不到这样做的方法。如果有一种方法可以使用匹配器中的服务。

更新 1:有些人要求我使用服务来确定要加载的模块,所以我创建了一个近似的canActivate外观。

@Injectable()
export class CanActivateRole implements CanActivate {
  constructor(private auth: AuthService, private router: Router) {}

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): boolean {
    // If not logged in
    if (this.auth.notLoggedIn() || this.auth.UserType == null) {
      this.router.navigateByUrl('/login');
      return false;
    }

    let routeData = route.data as CustomRouteData;

    if (routeData.roles == undefined) {
      // Is authenticated but no roles specified so allowed through
      return true;
    } 
    else if (Array.isArray(routeData.roles)) {
      routeData.roles.forEach(allowedRole => {
        if (this.auth.allowParentPermission(allowedRole, this.auth.UserType)) {
          return true;
        }
        return false;
      });
    }
    else {
      if (this.auth.allowParentPermission(routeData.roles, this.auth.UserType)) {
        return true;
      }
    }

    return false;
  }
}

我尝试做的另一种选择是某种服务,它返回要加载的模块loadChildren

@Injectable()
export class RouteMatcher {
  constructor(private auth: AuthService) {}

  /**
   * Used to match user roles to route to modules.
   *
   * To use return function in loadChildren key in routes eg.
   * ```
   * {
   *  path: '',
   *  loadChildren: () => return userRoleModuleMatcher(obj);
   * }
   * ```
   *
   * `Obj`: A map of which UserType or list of UserTypes will be matched onto a module. That module will route all of it's children to the original router. Eg.
   * `[[DCRoleType, EmpRoleType], EmpModule]`
   * will match both `DCRoleType` and `EmpRoleType` onto the `EmpModule`
   */
  public userRoleModuleMatcher(
    obj: ReadonlyMap<
      typeof UserType.UserType[] | typeof UserType.UserType,
      any
    >
  ): any {
    obj.forEach((module, allowedRoles) => {
        if (Array.isArray(allowedRoles)) {
            allowedRoles.forEach(role => {
              if (this.auth.allowParentPermission(role, this.auth.UserType)) {
                return module;
              }
            });
          }
          else {
            if (this.auth.allowParentPermission(allowedRoles, this.auth.UserType)) {
              return module;
          }
        }

        // If there are no matching permissions then route to shared module which has Server Error component
        return SharedModule;
    });
  }
}
4

1 回答 1

1

我认为这不可能作为路线匹配canActive的运行。

我认为让角色成为路线的一部分是这里的简单解决方案,

const routes: CustomRoutes = [
  { path: 'login', component: LoginFormComponent },
  {
    path: 'client',
    canActivate: [CanActivateRole],
    data: {
      roles: UserType.ClientRoleType
    }, 
    loadChildren: () => { return ClientModule; },
  },
  {
    path: 'dc',
    canActivate: [CanActivateRole],
    data: {
      roles: UserType.DCRoleType
    }, 
    loadChildren: () => { return DcEmpModule; },
  },
];

(不是实际代码,只是一个想法!)

于 2021-09-06T05:38:21.897 回答