30e100ef3e
2. 添加权限映射表和全局查看权限的hook,便于路由控制不同权限按钮显示/隐藏。 3. 删除评查点分组的部分旧api方法。 4. 对接评查点分组接口,文档类型接口, 提示词管理接口, 入口模块管理的接口。 5. 优化角色权限管理的接口,完善不用地区的访问权限认证。 6. 优化主页交叉评查和设置的入口样式和布局。 7. 优化评查点分组,评查规则的功能权限校验。
273 lines
7.3 KiB
TypeScript
273 lines
7.3 KiB
TypeScript
/**
|
|
* 权限检查Hook
|
|
*
|
|
* 基于RBAC(基于角色的访问控制)模型,提供细粒度的权限检查功能。
|
|
*
|
|
* 权限键格式:module:resource:action
|
|
* 例如:prompt_template:create:write
|
|
*
|
|
* 使用示例:
|
|
* ```typescript
|
|
* const { hasPermission, canCreate, canEdit } = usePermission();
|
|
*
|
|
* // 检查单个权限
|
|
* if (hasPermission('prompt_template:create:write')) {
|
|
* // 显示创建按钮
|
|
* }
|
|
*
|
|
* // 使用便捷方法
|
|
* if (canCreate('prompt_template')) {
|
|
* // 显示创建按钮
|
|
* }
|
|
* ```
|
|
*/
|
|
|
|
import { useRouteLoaderData, useLocation } from "@remix-run/react";
|
|
|
|
interface RootLoaderData {
|
|
permissions?: string[];
|
|
permissionMap?: Record<string, string[]>; // ✅ 新增:权限映射表
|
|
userRole: string;
|
|
userInfo?: {
|
|
role_id?: number;
|
|
role_key?: string;
|
|
role_name?: string;
|
|
};
|
|
}
|
|
|
|
export function usePermission() {
|
|
const rootData = useRouteLoaderData("root") as RootLoaderData;
|
|
const location = useLocation();
|
|
|
|
// 从root loader获取权限映射表
|
|
const permissionMap = rootData?.permissionMap || {};
|
|
const userRole = rootData?.userRole || 'common';
|
|
|
|
// 🔑 根据当前路由获取权限列表
|
|
const currentPath = location.pathname;
|
|
// console.log('currentPath', currentPath)
|
|
const currentPermissions = permissionMap[currentPath] || [];
|
|
|
|
// 向后兼容:如果存在旧的permissions数组,也要支持
|
|
const legacyPermissions = rootData?.permissions || [];
|
|
|
|
/**
|
|
* 检查是否有指定权限
|
|
* @param permissionKey 权限键,如 "prompt_template:create:write"
|
|
* @returns boolean
|
|
*/
|
|
const hasPermission = (permissionKey: string): boolean => {
|
|
// 优先使用当前路由的权限列表
|
|
if (currentPermissions.length > 0) {
|
|
return currentPermissions.includes(permissionKey);
|
|
}
|
|
|
|
// 向后兼容:支持旧的permissions数组
|
|
if (legacyPermissions.length > 0) {
|
|
return legacyPermissions.includes(permissionKey);
|
|
}
|
|
|
|
// 降级方案:如果没有权限数据,使用userRole判断(兼容现有系统)
|
|
// 包含'provin'的角色拥有所有权限
|
|
if (userRole.toLowerCase().includes('provin')) {
|
|
return true;
|
|
}
|
|
|
|
// 默认只有查看权限
|
|
if (permissionKey.includes(':read')) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* 检查是否有指定路由的权限
|
|
* @param path 路由路径,如 "/prompts"
|
|
* @param permissionKey 权限键
|
|
* @returns boolean
|
|
*/
|
|
const hasRoutePermission = (path: string, permissionKey: string): boolean => {
|
|
const routePermissions = permissionMap[path] || [];
|
|
return routePermissions.includes(permissionKey);
|
|
};
|
|
|
|
/**
|
|
* 获取当前路由的所有权限
|
|
* @returns 权限列表
|
|
*/
|
|
const getCurrentPermissions = (): string[] => {
|
|
return currentPermissions;
|
|
};
|
|
|
|
/**
|
|
* 获取指定路由的所有权限
|
|
* @param path 路由路径
|
|
* @returns 权限列表
|
|
*/
|
|
const getRoutePermissions = (path: string): string[] => {
|
|
return permissionMap[path] || [];
|
|
};
|
|
|
|
/**
|
|
* 检查是否有指定模块的任意权限
|
|
* @param module 模块名,如 "prompt_template"
|
|
* @returns boolean
|
|
*/
|
|
const hasModulePermission = (module: string): boolean => {
|
|
if (currentPermissions.length > 0) {
|
|
return currentPermissions.some(p => p.startsWith(`${module}:`));
|
|
}
|
|
|
|
if (legacyPermissions.length > 0) {
|
|
return legacyPermissions.some(p => p.startsWith(`${module}:`));
|
|
}
|
|
|
|
// 降级方案
|
|
return userRole.toLowerCase().includes('provin');
|
|
};
|
|
|
|
/**
|
|
* 检查是否有指定资源和动作的权限
|
|
* @param module 模块名,如 "prompt_template"
|
|
* @param resource 资源名,如 "create", "list", "detail"
|
|
* @param action 动作,如 "read", "write", "delete"
|
|
* @returns boolean
|
|
*/
|
|
const hasResourcePermission = (module: string, resource: string, action: string): boolean => {
|
|
const permissionKey = `${module}:${resource}:${action}`;
|
|
return hasPermission(permissionKey);
|
|
};
|
|
|
|
/**
|
|
* 批量检查权限(需要全部满足)
|
|
* @param permissionKeys 权限键数组
|
|
* @returns boolean
|
|
*/
|
|
const hasAllPermissions = (permissionKeys: string[]): boolean => {
|
|
return permissionKeys.every(key => hasPermission(key));
|
|
};
|
|
|
|
/**
|
|
* 批量检查权限(满足任意一个即可)
|
|
* @param permissionKeys 权限键数组
|
|
* @returns boolean
|
|
*/
|
|
const hasAnyPermission = (permissionKeys: string[]): boolean => {
|
|
return permissionKeys.some(key => hasPermission(key));
|
|
};
|
|
|
|
// 便捷方法:检查常见操作权限
|
|
const canCreate = (module: string): boolean => {
|
|
return hasResourcePermission(module, 'create', 'write');
|
|
};
|
|
|
|
const canRead = (module: string, resource: string = 'list'): boolean => {
|
|
return hasResourcePermission(module, resource, 'read');
|
|
};
|
|
|
|
const canUpdate = (module: string): boolean => {
|
|
return hasResourcePermission(module, 'update', 'write');
|
|
};
|
|
|
|
const canDelete = (module: string): boolean => {
|
|
return hasResourcePermission(module, 'delete', 'delete');
|
|
};
|
|
|
|
const canList = (module: string): boolean => {
|
|
return hasResourcePermission(module, 'list', 'read');
|
|
};
|
|
|
|
const canView = (module: string): boolean => {
|
|
return hasResourcePermission(module, 'detail', 'read');
|
|
};
|
|
|
|
/**
|
|
* 检查是否有批量操作权限
|
|
* @param module 模块名,如 "evaluation_group"
|
|
* @returns boolean - 检查是否有 module:batch:write 权限
|
|
*/
|
|
const canBatch = (module: string): boolean => {
|
|
return hasResourcePermission(module, 'batch', 'write');
|
|
};
|
|
|
|
return {
|
|
// 原始权限数据
|
|
permissions: currentPermissions, // ✅ 返回当前路由的权限
|
|
permissionMap, // ✅ 返回完整的权限映射表
|
|
userRole,
|
|
|
|
// 基础检查方法
|
|
hasPermission,
|
|
hasModulePermission,
|
|
hasResourcePermission,
|
|
hasAllPermissions,
|
|
hasAnyPermission,
|
|
|
|
// ✅ 新增:路由权限查询方法
|
|
hasRoutePermission,
|
|
getCurrentPermissions,
|
|
getRoutePermissions,
|
|
|
|
// 便捷方法
|
|
canCreate,
|
|
canRead,
|
|
canUpdate,
|
|
canDelete,
|
|
canList,
|
|
canView,
|
|
canBatch // ✅ 新增:批量操作权限检查
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 权限组件包装器
|
|
*
|
|
* 根据权限控制子组件的显示/隐藏
|
|
*
|
|
* 使用示例:
|
|
* ```typescript
|
|
* <PermissionGuard permission="prompt_template:create:write">
|
|
* <Button>新增模板</Button>
|
|
* </PermissionGuard>
|
|
* ```
|
|
*/
|
|
interface PermissionGuardProps {
|
|
permission?: string;
|
|
permissions?: string[];
|
|
requireAll?: boolean; // true=需要全部权限,false=任意一个即可
|
|
fallback?: React.ReactNode; // 无权限时显示的内容
|
|
children: React.ReactNode;
|
|
}
|
|
|
|
export function PermissionGuard({
|
|
permission,
|
|
permissions: permissionList,
|
|
requireAll = false,
|
|
fallback = null,
|
|
children
|
|
}: PermissionGuardProps) {
|
|
const { hasPermission, hasAllPermissions, hasAnyPermission } = usePermission();
|
|
|
|
let hasAccess = false;
|
|
|
|
if (permission) {
|
|
// 单个权限检查
|
|
hasAccess = hasPermission(permission);
|
|
} else if (permissionList && permissionList.length > 0) {
|
|
// 多个权限检查
|
|
hasAccess = requireAll
|
|
? hasAllPermissions(permissionList)
|
|
: hasAnyPermission(permissionList);
|
|
} else {
|
|
// 没有指定权限,默认允许访问
|
|
hasAccess = true;
|
|
}
|
|
|
|
if (!hasAccess) {
|
|
return <>{fallback}</>;
|
|
}
|
|
|
|
return <>{children}</>;
|
|
}
|