自定义DjangoModelPermissions未生效,如何按组织成员权限限制Widget操作?
问题原因分析
你的权限未生效主要有两个核心问题:
- 列表/创建动作未触发组织归属检查:
ModelViewSet的list、create等动作仅调用has_permission方法,而你继承的DjangoModelPermissions默认只验证模型级权限(如view_widget),不会检查用户与当前组织的归属关系。 - 对象级权限的类型不匹配:
obj.organization_id是UUID对象,而request.user.user_organization_ids是字符串列表,直接用in判断会因类型不一致导致匹配失败,本该拦截的请求被错误允许。
修复后的自定义权限类
同时重写has_permission和has_object_permission,覆盖模型级和对象级的权限校验逻辑:
from rest_framework.permissions import DjangoModelPermissions from rest_framework.exceptions import PermissionDenied class OrganizationPermission(DjangoModelPermissions): def has_permission(self, request, view): # 先执行父类的模型权限检查(确保用户拥有对应模型的操作权限) has_model_perm = super().has_permission(request, view) if not has_model_perm: return False # 从URL参数中获取组织ID,适配你的路由设计 org_id = view.kwargs.get('organization_id') if org_id: return org_id in request.user.user_organization_ids # 处理创建动作:从请求数据中提取组织ID并验证归属 if request.method == 'POST': org_id = request.data.get('organization_id') if org_id and org_id in request.user.user_organization_ids: return True raise PermissionDenied("你无权在该组织下创建资源") # 无明确组织ID的场景(如全局列表),根据业务需求调整返回逻辑 return False def has_object_permission(self, request, view, obj): # 校验对象是否包含组织ID属性 if not hasattr(obj, 'organization_id') or obj.organization_id is None: return False # 将对象的组织ID转为字符串,与用户的组织ID列表匹配 obj_org_id = str(obj.organization_id) return obj_org_id in request.user.user_organization_ids
额外注意事项
- 路由适配:确保你的Widget路由包含
organization_id参数,示例如下:# urls.py from rest_framework.routers import DefaultRouter from .views import WidgetViewSet router = DefaultRouter() router.register(r'organizations/(?P<organization_id>[^/.]+)/widgets', WidgetViewSet) - 模型权限可选项:如果业务不需要严格的模型级权限(只要用户属于组织就允许操作),可以移除
super().has_permission的调用,但保留该逻辑更符合Django权限设计规范。 - create动作校验:通过
request.data提取组织ID并验证,避免用户在不属于自己的组织下创建Widget。
内容的提问来源于stack exchange,提问作者Joe F.
相关产品推荐
相关产品推荐

