基于Django默认模型权限实现对象级权限的方案是否存在弊端?
默认情况下,Django会为每个注册模型自动添加4种全局权限:
add_modelnamechange_modelnamedelete_modelnameview_modelname
这些权限默认作用于该模型的所有实例,但我需要对象级权限:仅允许模型创建者(数据库中created_by字段关联的用户)在拥有delete_modelname这类默认CRUD权限时,只能操作自己创建的实例,无法操作他人创建的实例。
我查阅的方案大多需要新建数据表或依赖第三方库,没看到利用默认自动生成的CRUD权限的思路,因此提出以下方案:
- 为模型创建者分配上述默认CRUD权限(这类权限原本允许操作所有实例)
- 自定义认证后端校验对象归属,代码如下:
from django.contrib.auth.backends import BaseBackend class ObjectPermissionBackend(BaseBackend): def has_perm(self, user_obj, perm, obj=None): if not obj: return False return obj.created_by == user_obj.pk # 校验对象归属
- 在配置中启用该后端:
AUTHENTICATION_BACKENDS = ['django.contrib.auth.backends.ModelBackend', 'path.to.ObjectPermissionBackend']
请问该方案是否存在弊端?
你的思路能实现基础的对象级权限控制,但存在不少明显问题:
全局权限逻辑冲突
默认的ModelBackend会先判断用户是否拥有全局的delete_modelname权限,Django的权限校验逻辑是只要有一个后端返回True就会通过。这意味着如果用户被分配了全局删除权限,他们依然能删除所有实例,你的自定义后端校验会被直接绕过。无对象场景的权限判断失效
Django中很多权限校验场景不会传入obj(比如判断用户是否能进入模型列表页、是否能发起创建请求),你的自定义后端在obj=None时直接返回False,会导致即使用户有全局的add_modelname权限,也无法通过这类无对象的权限校验,直接阻断正常的创建、列表查看等操作。权限粒度无法扩展
如果后续需要给非创建者分配特定实例的权限(比如管理员给某个用户开放他人创建实例的编辑权限),你的方案完全无法支持——它只校验created_by字段,没有预留任何扩展空间。与Django原生权限体系兼容性差
Django的权限系统默认基于模型级设计,你的自定义后端会打破这个约定,导致和依赖默认权限逻辑的第三方库、Admin后台等组件兼容性变差。比如Django Admin会根据模型级权限判断用户是否能访问管理界面,你的后端会干扰这个逻辑,可能导致Admin功能异常。代码复用性低
如果多个模型都需要对象级权限,你要么为每个模型单独调整has_perm的校验逻辑,要么额外做抽象处理,否则会产生大量重复代码,后期维护成本极高。
内容的提问来源于stack exchange,提问作者himmip

