refactor: optimze merge role snippets

This commit is contained in:
霍世杰 2025-02-23 23:33:46 +08:00
parent ee05e2dd22
commit ad74362e18
2 changed files with 28 additions and 16 deletions

View File

@ -7,7 +7,6 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { ACLRole } from '@nocobase/acl';
import { mergeRole } from '../utils'; import { mergeRole } from '../utils';
const map2obj = (map: Map<string, string>) => { const map2obj = (map: Map<string, string>) => {

View File

@ -17,14 +17,18 @@ export function mergeRole(roles) {
snippets: [], snippets: [],
resources: null, resources: null,
}; };
const allSnippets: string[][] = [];
for (const role of roles) { for (const role of roles) {
const jsonRole = role.toJSON(); const jsonRole = role.toJSON();
result.roles = mergeRoleNames(result.roles, jsonRole.role); result.roles = mergeRoleNames(result.roles, jsonRole.role);
result.strategy = mergeRoleStrategy(result.strategy, jsonRole.strategy); result.strategy = mergeRoleStrategy(result.strategy, jsonRole.strategy);
result.actions = mergeRoleActions(result.actions, jsonRole.actions); result.actions = mergeRoleActions(result.actions, jsonRole.actions);
result.snippets = mergeRoleSnippets(result.snippets, jsonRole.snippets);
result.resources = mergeRoleResources(result.resources, [...role.resources.keys()]); result.resources = mergeRoleResources(result.resources, [...role.resources.keys()]);
if (_.isArray(jsonRole.snippets)) {
allSnippets.push(jsonRole.snippets);
}
} }
result.snippets = mergeRoleSnippets(allSnippets);
return result; return result;
} }
@ -55,22 +59,31 @@ function mergeRoleActions(sourceActions, newActions) {
return _.merge(sourceActions, newActions); return _.merge(sourceActions, newActions);
} }
function mergeRoleSnippets(sourceSnippets, newSnippets = []) { function mergeRoleSnippets(allRoleSnippets: string[][]): string[] {
const allSnippets = [...sourceSnippets, ...newSnippets]; if (!allRoleSnippets.length) {
return [];
}
const result = allSnippets.reduce((acc, snippet) => { const allSnippets = allRoleSnippets.flat();
// 去重 const isExclusion = (value) => value.startsWith('!');
if (acc.includes(snippet)) { const includes = new Set(allSnippets.filter((x) => !isExclusion(x)));
return acc; const excludes = new Set(allSnippets.filter((x) => isExclusion(x)));
// 处理黑名单的交集:比如 ['a.*', '!a.b.*'] 和 ['a.*', '!a.b.*', '!a.c.*'],最终取 ['a.*', '!a.b.*']
const excludesSet = new Set<string>();
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))) { // 处理冲突项,比如 ['a'] 和 ['!a'],最终取 ['a']
return acc; excludesSet.forEach((x) => includes.has(x.slice(1)) && excludesSet.delete(x));
}
acc.push(snippet); const result = [...includes];
return acc; excludesSet.forEach((x) => result.push(x));
}, []);
return result; return result;
} }