From ad74362e1817b5c6062d18aebfe04f84115b0ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9C=8D=E4=B8=96=E6=9D=B0?= Date: Sun, 23 Feb 2025 23:33:46 +0800 Subject: [PATCH] refactor: optimze merge role snippets --- .../src/server/actions/role-check.ts | 1 - .../plugin-acl/src/server/utils/role.ts | 43 ++++++++++++------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/packages/plugins/@nocobase/plugin-acl/src/server/actions/role-check.ts b/packages/plugins/@nocobase/plugin-acl/src/server/actions/role-check.ts index 84020db9e6..1a02031d5b 100644 --- a/packages/plugins/@nocobase/plugin-acl/src/server/actions/role-check.ts +++ b/packages/plugins/@nocobase/plugin-acl/src/server/actions/role-check.ts @@ -7,7 +7,6 @@ * For more information, please refer to: https://www.nocobase.com/agreement. */ -import { ACLRole } from '@nocobase/acl'; import { mergeRole } from '../utils'; const map2obj = (map: Map) => { diff --git a/packages/plugins/@nocobase/plugin-acl/src/server/utils/role.ts b/packages/plugins/@nocobase/plugin-acl/src/server/utils/role.ts index 612e1fc69c..67ed918426 100644 --- a/packages/plugins/@nocobase/plugin-acl/src/server/utils/role.ts +++ b/packages/plugins/@nocobase/plugin-acl/src/server/utils/role.ts @@ -17,14 +17,18 @@ export function mergeRole(roles) { snippets: [], resources: null, }; + const allSnippets: string[][] = []; for (const role of roles) { const jsonRole = role.toJSON(); result.roles = mergeRoleNames(result.roles, jsonRole.role); result.strategy = mergeRoleStrategy(result.strategy, jsonRole.strategy); result.actions = mergeRoleActions(result.actions, jsonRole.actions); - result.snippets = mergeRoleSnippets(result.snippets, jsonRole.snippets); result.resources = mergeRoleResources(result.resources, [...role.resources.keys()]); + if (_.isArray(jsonRole.snippets)) { + allSnippets.push(jsonRole.snippets); + } } + result.snippets = mergeRoleSnippets(allSnippets); return result; } @@ -55,22 +59,31 @@ function mergeRoleActions(sourceActions, newActions) { return _.merge(sourceActions, newActions); } -function mergeRoleSnippets(sourceSnippets, newSnippets = []) { - const allSnippets = [...sourceSnippets, ...newSnippets]; +function mergeRoleSnippets(allRoleSnippets: string[][]): string[] { + if (!allRoleSnippets.length) { + return []; + } - const result = allSnippets.reduce((acc, snippet) => { - // 去重 - if (acc.includes(snippet)) { - return acc; + const allSnippets = allRoleSnippets.flat(); + const isExclusion = (value) => value.startsWith('!'); + const includes = new Set(allSnippets.filter((x) => !isExclusion(x))); + const excludes = new Set(allSnippets.filter((x) => isExclusion(x))); + + // 处理黑名单的交集:比如 ['a.*', '!a.b.*'] 和 ['a.*', '!a.b.*', '!a.c.*'],最终取 ['a.*', '!a.b.*'] + const excludesSet = new Set(); + excludes.forEach((snippet) => { + // 取交集:所有角色都有这个黑名单 + const allHas = allRoleSnippets.every((x) => x.includes(snippet)); + if (allHas) { + excludesSet.add(snippet); } - // 当前是 !xxx 并且已经有 xxx,!xxx 则不需要生效 - const isExclusion = snippet.startsWith('!'); - if (isExclusion && acc.includes(snippet.slice(1))) { - return acc; - } - acc.push(snippet); - return acc; - }, []); + }); + + // 处理冲突项,比如 ['a'] 和 ['!a'],最终取 ['a'] + excludesSet.forEach((x) => includes.has(x.slice(1)) && excludesSet.delete(x)); + + const result = [...includes]; + excludesSet.forEach((x) => result.push(x)); return result; }