/** * 权限键映射工具 * 用于将数据库中的权限键映射为前端显示的权限键 * * 问题背景: * 数据库中的权限键(dify:bind:*)与路由实际检查的权限键(dify:dataset:*, dify:file:*)不一致 * 导致前端取消勾选后,后端仍然检查实际权限,权限控制失效 */ /** * 权限键映射表 * key: 数据库中的权限键 * value: 前端显示和实际生效的权限键 */ const PERMISSION_KEY_MAP: Record = { // 知识库绑定相关 - 映射到数据集管理权限 'dify:bind:list': 'dify:dataset:manage', 'dify:bind:create': 'dify:dataset:manage', 'dify:bind:update': 'dify:dataset:manage', 'dify:bind:delete': 'dify:dataset:manage', }; /** * 反向映射表:实际权限键 -> 数据库权限键列表 * 用于检查某个权限是否被正确配置 */ const REVERSE_PERMISSION_MAP: Record = { 'dify:dataset:manage': [ 'dify:bind:list', 'dify:bind:create', 'dify:bind:update', 'dify:bind:delete', ], }; /** * 将数据库权限键转换为显示权限键 * @param permissionKey 数据库中的权限键 * @returns 前端显示的权限键 * * @example * mapPermissionKey('dify:bind:list') // 返回 'dify:dataset:manage' * mapPermissionKey('dify:file:read') // 返回 'dify:file:read'(无映射) */ export function mapPermissionKey(permissionKey: string): string { return PERMISSION_KEY_MAP[permissionKey] || permissionKey; } /** * 批量转换权限键列表 * @param permissionKeys 权限键数组 * @returns 转换后的权限键数组(去重) */ export function mapPermissionKeys(permissionKeys: string[]): string[] { const mappedKeys = permissionKeys.map(key => mapPermissionKey(key)); return [...new Set(mappedKeys)]; // 去重 } /** * 反向查找:根据实际权限键找到对应的数据库权限键列表 * @param effectivePermissionKey 实际生效的权限键(如 'dify:dataset:manage') * @returns 对应的数据库权限键列表 * * @example * findDbPermissionKeys('dify:dataset:manage') * // 返回 ['dify:bind:list', 'dify:bind:create', 'dify:bind:update', 'dify:bind:delete'] */ export function findDbPermissionKeys(effectivePermissionKey: string): string[] { return REVERSE_PERMISSION_MAP[effectivePermissionKey] || [effectivePermissionKey]; } /** * 转换权限对象:将数据库权限对象转换为显示权限对象 * @param permission 权限对象(来自数据库) * @returns 转换后的权限对象 */ export interface Permission { id: number; permission_key: string; display_name: string; api_method?: string; api_path?: string; [key: string]: any; } export function mapPermission(permission: Permission): Permission { const mappedKey = mapPermissionKey(permission.permission_key); // 如果权限键被映射,更新显示名称(可选) let displayName = permission.display_name; if (mappedKey !== permission.permission_key) { // 根据映射后的权限键更新显示名称 if (mappedKey === 'dify:dataset:manage') { displayName = '知识库管理(查看、创建、编辑、删除)'; } } return { ...permission, permission_key: mappedKey, display_name: displayName, }; } /** * 批量转换权限列表 * @param permissions 权限对象数组 * @returns 转换后的权限对象数组(去重) */ export function mapPermissions(permissions: Permission[]): Permission[] { const mappedMap = new Map(); permissions.forEach(permission => { const mapped = mapPermission(permission); // 如果映射后的权限键已存在,合并(保留第一个或根据业务逻辑) if (!mappedMap.has(mapped.permission_key)) { mappedMap.set(mapped.permission_key, mapped); } }); return Array.from(mappedMap.values()); } /** * 检查权限是否受映射影响 * @param permissionKey 权限键 * @returns 是否有映射关系 */ export function hasPermissionMapping(permissionKey: string): boolean { return PERMISSION_KEY_MAP[permissionKey] !== undefined; } /** * 获取权限映射的说明信息 * @returns 映射关系的说明文本 */ export function getPermissionMappingInfo(): string { return `权限映射说明:\n` + `- dify:bind:list/create/update/delete → dify:dataset:manage(知识库管理)\n` + `取消勾选后,对应接口将返回403权限不足错误`; }