forked from hangshuo652/aurak
feat: 分层 RBAC 权限管理系统
后端: - 新增 Role / RolePermission 实体(自动 seed 系统角色) - PermissionService——通过 isAdmin / TenantMember 链路解析用户权限 - @Permission() 装饰器 + PermissionsGuard 守卫 - /api/permissions 和 /api/roles REST API - UserController 内联 role 检查迁移到 @Permission() - PermissionModule 全局注册 前端: - usePermissions hook——获取当前用户权限集 - PermissionGate 组件级门控 - PermissionSettingsView——角色列表+权限矩阵编辑页面 - SettingsView 新增「权限管理」Tab(仅 admin 可见) - 权限预览(26 项,7 分类) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useAuth } from '../contexts/AuthContext';
|
||||
|
||||
/**
|
||||
* 前端权限 hook
|
||||
* 获取当前用户在活动租户下的权限集,提供便捷的检查方法
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const { hasPermission, hasAnyPermission, isLoading } = usePermissions();
|
||||
*
|
||||
* if (hasPermission('user:create')) {
|
||||
* // 渲染创建用户按钮
|
||||
* }
|
||||
*
|
||||
* {hasAnyPermission('user:edit', 'user:delete') && <AdminActions />}
|
||||
* ```
|
||||
*/
|
||||
export function usePermissions() {
|
||||
const { apiKey, activeTenant } = useAuth();
|
||||
const [permissions, setPermissions] = useState<string[]>([]);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const fetchPermissions = useCallback(async () => {
|
||||
if (!apiKey || !activeTenant) {
|
||||
setPermissions([]);
|
||||
setIsLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const res = await fetch('/api/permissions/mine', {
|
||||
headers: {
|
||||
'x-api-key': apiKey,
|
||||
'x-tenant-id': activeTenant.tenantId,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
setPermissions(data.permissions || []);
|
||||
setError(null);
|
||||
} else {
|
||||
setPermissions([]);
|
||||
}
|
||||
} catch (err: any) {
|
||||
console.error('Failed to fetch permissions:', err);
|
||||
setError(err.message);
|
||||
setPermissions([]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [apiKey, activeTenant?.tenantId]);
|
||||
|
||||
// 获取权限
|
||||
useEffect(() => {
|
||||
fetchPermissions();
|
||||
}, [fetchPermissions]);
|
||||
|
||||
const hasPermission = useCallback(
|
||||
(key: string) => permissions.includes(key),
|
||||
[permissions],
|
||||
);
|
||||
|
||||
const hasAnyPermission = useCallback(
|
||||
(...keys: string[]) => keys.some(k => permissions.includes(k)),
|
||||
[permissions],
|
||||
);
|
||||
|
||||
const hasAllPermissions = useCallback(
|
||||
(...keys: string[]) => keys.every(k => permissions.includes(k)),
|
||||
[permissions],
|
||||
);
|
||||
|
||||
return {
|
||||
permissions,
|
||||
isLoading,
|
||||
error,
|
||||
hasPermission,
|
||||
hasAnyPermission,
|
||||
hasAllPermissions,
|
||||
refresh: fetchPermissions,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user