From bd9faa89bd174f9b535e3003fd1937be2beeb13d Mon Sep 17 00:00:00 2001 From: zhangzhanwei Date: Thu, 25 Dec 2025 11:09:02 +0800 Subject: [PATCH] fix: Folder auth permission --- apps/common/constants/permission_constants.py | 6 +-- apps/folders/serializers/folder.py | 40 +++++++++++++++---- .../views/user_resource_permission.py | 18 ++++----- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/apps/common/constants/permission_constants.py b/apps/common/constants/permission_constants.py index 6fbe11472..564c7b3b8 100644 --- a/apps/common/constants/permission_constants.py +++ b/apps/common/constants/permission_constants.py @@ -558,7 +558,7 @@ class PermissionConstants(Enum): ) TOOL_FOLDER_READ = Permission( group=Group.TOOL_FOLDER, operate=Operate.READ, role_list=[RoleConstants.ADMIN, RoleConstants.USER], - parent_group=[WorkspaceGroup.TOOL, UserGroup.TOOL], + parent_group=[UserGroup.TOOL], resource_permission_group_list=[ResourcePermissionConst.TOOL_VIEW] ) TOOL_FOLDER_CREATE = Permission( @@ -629,7 +629,7 @@ class PermissionConstants(Enum): KNOWLEDGE_FOLDER_READ = Permission( group=Group.KNOWLEDGE_FOLDER, operate=Operate.READ, role_list=[RoleConstants.ADMIN, RoleConstants.USER], resource_permission_group_list=[ResourcePermissionConst.KNOWLEDGE_VIEW], - parent_group = [WorkspaceGroup.KNOWLEDGE, UserGroup.KNOWLEDGE] + parent_group = [UserGroup.KNOWLEDGE] ) KNOWLEDGE_FOLDER_CREATE = Permission( group=Group.KNOWLEDGE_FOLDER, operate=Operate.CREATE, role_list=[RoleConstants.ADMIN, RoleConstants.USER], @@ -961,7 +961,7 @@ class PermissionConstants(Enum): ) APPLICATION_FOLDER_READ = Permission(group=Group.APPLICATION_FOLDER, operate=Operate.READ, role_list=[RoleConstants.ADMIN, RoleConstants.USER], - parent_group=[WorkspaceGroup.APPLICATION, UserGroup.APPLICATION], + parent_group=[UserGroup.APPLICATION], resource_permission_group_list=[ResourcePermissionConst.APPLICATION_VIEW] ) APPLICATION_FOLDER_CREATE = Permission(group=Group.APPLICATION_FOLDER, operate=Operate.CREATE, diff --git a/apps/folders/serializers/folder.py b/apps/folders/serializers/folder.py index b9f9babf1..93e748f1c 100644 --- a/apps/folders/serializers/folder.py +++ b/apps/folders/serializers/folder.py @@ -10,7 +10,8 @@ from rest_framework import serializers from application.models.application import Application, ApplicationFolder from application.serializers.application import ApplicationOperateSerializer from application.serializers.application_folder import ApplicationFolderTreeSerializer -from common.constants.permission_constants import Group, ResourcePermission, ResourcePermissionRole +from common.constants.permission_constants import Group, ResourcePermission, ResourcePermissionRole, RoleConstants +from common.database_model_manage.database_model_manage import DatabaseModelManage from common.exception.app_exception import AppApiException from folders.api.folder import FolderCreateRequest from knowledge.models import KnowledgeFolder, Knowledge @@ -300,30 +301,52 @@ class FolderTreeSerializer(serializers.Serializer): return True # 需要重建 return False + @staticmethod + def _having_read_permission_by_role(user_id: str, workspace_id: str, source: str): + workspace_user_role_mapping_model = DatabaseModelManage.get_model("workspace_user_role_mapping") + role_permission_mapping_model = DatabaseModelManage.get_model("role_permission_mapping_model") + is_x_pack_ee = workspace_user_role_mapping_model is not None and role_permission_mapping_model is not None + if is_x_pack_ee: + return QuerySet(workspace_user_role_mapping_model).select_related('role', 'user').filter( + workspace_id=workspace_id, user_id=user_id, + role__type=RoleConstants.USER.value.__str__(), + role__rolepermission__permission_id=f"{source}_FOLDER:READ" + ).exists() + + return False + def get_folder_tree(self, current_user, name=None): self.is_valid(raise_exception=True) - Folder = get_folder_type(self.data.get('source')) # noqa + user_id = current_user.id + workspace_id = self.data.get('workspace_id') + source = self.data.get('source') + + Folder = get_folder_type(source) # noqa # 检查特定工作空间的树结构完整性 - workspace_folders = Folder.objects.filter(workspace_id=self.data.get('workspace_id')) - + workspace_folders = Folder.objects.filter(workspace_id=workspace_id) # 如果发现数据不一致,重建整个表(这是 MPTT 的限制) if self._check_tree_integrity(workspace_folders): Folder.objects.rebuild() - workspace_manage = is_workspace_manage(current_user.id, self.data.get('workspace_id')) + workspace_manage = is_workspace_manage(user_id, workspace_id) - base_q = Q(workspace_id=self.data.get('workspace_id')) + base_q = Q(workspace_id=workspace_id) if name is not None: base_q &= Q(name__contains=name) if not workspace_manage: + having_read_permission_by_role = self._having_read_permission_by_role(user_id, workspace_id, source) + permission_condition = ['VIEW'] + if having_read_permission_by_role: + permission_condition = ['VIEW', 'ROLE'] + base_q &= (Q(id__in=WorkspaceUserResourcePermission.objects.filter(user_id=current_user.id, auth_target_type=self.data.get('source'), workspace_id=self.data.get( 'workspace_id'), - permission_list__contains=['VIEW']) + permission_list__overlap=permission_condition) .values_list( 'target', flat=True)) | Q(id=self.data.get('workspace_id'))) @@ -332,4 +355,5 @@ class FolderTreeSerializer(serializers.Serializer): TreeSerializer = get_folder_tree_serializer(self.data.get('source')) # noqa serializer = TreeSerializer(nodes, many=True) - return [d for d in serializer.data if d.get('id') == d.get('workspace_id')] if name is None else serializer.data # 这是可序列化的字典 + return [d for d in serializer.data if + d.get('id') == d.get('workspace_id')] if name is None else serializer.data # 这是可序列化的字典 diff --git a/apps/system_manage/views/user_resource_permission.py b/apps/system_manage/views/user_resource_permission.py index 68cd61459..4bcfbe7b3 100644 --- a/apps/system_manage/views/user_resource_permission.py +++ b/apps/system_manage/views/user_resource_permission.py @@ -120,16 +120,16 @@ class WorkspaceResourceUserPermissionView(APIView): resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}:ROLE/WORKSPACE_MANAGE"), lambda r, kwargs: Permission(group=Group(kwargs.get('resource')), operate=Operate.AUTH, - resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}"), + resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}"), ViewPermission([RoleConstants.USER.get_workspace_role()], [lambda r, kwargs: Permission(group=Group(kwargs.get('resource')), operate=Operate.SELF, - resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}")], + resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}")], CompareConstants.AND), RoleConstants.WORKSPACE_MANAGE.get_workspace_role()) def get(self, request: Request, workspace_id: str, target: str, resource: str): return result.success(ResourceUserPermissionSerializer( - data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource, + data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource.replace('_FOLDER',''), }).list( {'username': request.query_params.get("username"), 'nick_name': request.query_params.get("nick_name"), 'permission': request.query_params.getlist("permission[]") @@ -154,16 +154,16 @@ class WorkspaceResourceUserPermissionView(APIView): resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}:ROLE/WORKSPACE_MANAGE"), lambda r, kwargs: Permission(group=Group(kwargs.get('resource')), operate=Operate.AUTH, - resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}"), + resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}"), ViewPermission([RoleConstants.USER.get_workspace_role()], [lambda r, kwargs: Permission(group=Group(kwargs.get('resource')), operate=Operate.SELF, - resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}")], + resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}")], CompareConstants.AND), RoleConstants.WORKSPACE_MANAGE.get_workspace_role()) def put(self, request: Request, workspace_id: str, target: str, resource: str): return result.success(ResourceUserPermissionSerializer( - data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource, }) + data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource.replace('_FOLDER',''), }) .edit(instance=request.data, current_user_id=request.user.id)) class Page(APIView): @@ -184,17 +184,17 @@ class WorkspaceResourceUserPermissionView(APIView): resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}:ROLE/WORKSPACE_MANAGE"), lambda r, kwargs: Permission(group=Group(kwargs.get('resource')), operate=Operate.AUTH, - resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}"), + resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}"), ViewPermission([RoleConstants.USER.get_workspace_role()], [lambda r, kwargs: Permission(group=Group(kwargs.get('resource')), operate=Operate.SELF, - resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource')}/{kwargs.get('target')}")], + resource_path=f"/WORKSPACE/{kwargs.get('workspace_id')}/{kwargs.get('resource').replace('_FOLDER','')}/{kwargs.get('target')}")], CompareConstants.AND), RoleConstants.WORKSPACE_MANAGE.get_workspace_role()) def get(self, request: Request, workspace_id: str, target: str, resource: str, current_page: int, page_size: int): return result.success(ResourceUserPermissionSerializer( - data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource, } + data={'workspace_id': workspace_id, "target": target, 'auth_target_type': resource.replace('_FOLDER',''), } ).page({'username': request.query_params.get("username"), 'role': request.query_params.get("role"), 'nick_name': request.query_params.get("nick_name"),