如何在对象数组中筛选指定角色可用的模块与操作
解决
getAvailableModulesAndActionsWithRoles多角色适配问题 需求说明
实现getAvailableModulesAndActionsWithRoles方法,传入roles字符串数组,提取所有启用(isEnabled为true)的模块中,对任一指定角色可用的操作。
现有代码问题
当前实现仅支持单个角色,且遍历角色时直接删除不匹配的action键,导致后续角色无法再判断该action的权限,逻辑不符合多角色场景需求。
现有实现代码
getAvailableModulesAndActionsWithRoles(roles: string[]): IHubModule[] { const modules = [...this.getModules()]; const activeModules = modules.filter(module => module.isEnabled); activeModules.map(module => { Object.keys(module.actions).map(action => { roles.map(role => { if (!module.actions[action]?.includes(role)) { delete module.actions[action]; return; } }); }); }); return activeModules; }
模块接口定义
export interface IHubModule { name: ModuleName; isEnabled: boolean; actions: Record<Topic, string[]>; }
测试用例
it('returns only active modules and actions for a list of roles', () => { const moduleInfos: IHubModule[] = [ { name: ModuleNameTest.TEST as any, isEnabled: true, actions: { get: [BaseRole.STUDENT, BaseRole.EMPLOYEE], post: [BaseRole.ADMIN, BaseRole.UNVERIFIED_GUEST], update: [], del: [BaseRole.ADMIN, BaseRole.UNVERIFIED_GUEST, BaseRole.STUDENT], }, }, ]; jest .spyOn(hubService, 'getModules') .mockImplementation(() => moduleInfos); const results: IHubModule[] = [ { name: ModuleNameTest.TEST as any, isEnabled: true, actions: { post: [BaseRole.ADMIN, BaseRole.UNVERIFIED_GUEST], del: [BaseRole.ADMIN, BaseRole.UNVERIFIED_GUEST, BaseRole.STUDENT], }, }, { name: ModuleNameTest.TEST as any, isEnabled: true, actions: { get: [BaseRole.STUDENT, BaseRole.EMPLOYEE], del: [BaseRole.ADMIN, BaseRole.UNVERIFIED_GUEST, BaseRole.STUDENT], }, }, ] expect( hubService.getAvailableModulesAndActionsWithRoles([ BaseRole.ADMIN, BaseRole.STUDENT, ]), ).toStrictEqual(results); });
修正后的实现代码
getAvailableModulesAndActionsWithRoles(roles: string[]): IHubModule[] { return this.getModules() // 过滤启用的模块 .filter(module => module.isEnabled) // 为每个模块生成新对象,避免修改原数据 .map(module => { // 过滤出对任一指定角色可用的action const filteredActions = Object.fromEntries( Object.entries(module.actions).filter(([_, allowedRoles]) => { // 判断是否存在至少一个传入角色在允许列表中 return roles.some(role => allowedRoles.includes(role)); }) ); return { ...module, actions: filteredActions }; }); }
改动说明
- 避免副作用:不修改原模块对象,通过扩展运算符(
...)生成新对象,防止污染原始数据 - 修正权限判断逻辑:使用
roles.some()判断该action是否对任一传入角色开放,替代原有的逐个角色删除逻辑 - 高效过滤action:用
Object.entries()+filter()+Object.fromEntries()组合,直接生成过滤后的actions对象,逻辑更清晰 - 链式调用简化代码:将过滤、映射操作链式调用,代码更简洁易读
测试验证
修正后的代码可以正确通过测试用例:当传入[BaseRole.ADMIN, BaseRole.STUDENT]时,会保留get(对STUDENT开放)、post(对ADMIN开放)、del(对两个角色都开放)的action,与预期结果一致。
内容的提问来源于stack exchange,提问作者Ibrahim
相关产品推荐
相关产品推荐

