如何配置Django权限系统实现特定模型实例的细粒度权限控制
你可以通过Django官方提供的自定义授权后端能力实现该需求,这是最符合Django设计规范的实现方式,比修改Group模型的方案更优雅,同时支持单用户权限分配和组权限分配。
1. 新增项目权限关联模型
新增两个中间表,分别存储用户、用户组与特定项目绑定的权限,完全复用Django原生的Permission模型,不需要修改核心权限逻辑:
from django.db import models from django.contrib.auth.models import User, Group, Permission # 你的原有模型 class Project(models.Model): pass class Page(models.Model): project = models.ForeignKey(Project, on_delete=models.CASCADE) # 新增的权限关联模型 class ProjectUserPermission(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="project_permissions") project = models.ForeignKey(Project, on_delete=models.CASCADE) permission = models.ForeignKey(Permission, on_delete=models.CASCADE) class Meta: unique_together = ("user", "project", "permission") class ProjectGroupPermission(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE, related_name="project_permissions") project = models.ForeignKey(Project, on_delete=models.CASCADE) permission = models.ForeignKey(Permission, on_delete=models.CASCADE) class Meta: unique_together = ("group", "project", "permission")
2. 实现自定义授权后端
Django的授权后端支持自定义has_perm方法,且原生支持传入被校验的对象参数,完全匹配你的需求:
from django.contrib.auth.backends import BaseBackend class ProjectPermissionBackend(BaseBackend): def has_perm(self, user_obj, perm, obj=None): # 超级用户默认拥有所有权限 if user_obj.is_superuser: return True # 未传入对象时不做校验(或可按需保留默认全局权限校验逻辑) if obj is None: return False # 自动提取关联的Project实例,支持直接传入Page等子资源对象 project = obj.project if hasattr(obj, "project") else obj # 提取权限codename(perm格式为<app_label>.<codename>) perm_codename = perm.split(".")[-1] # 校验用户单独分配的项目权限 if user_obj.project_permissions.filter( project=project, permission__codename=perm_codename ).exists(): return True # 校验用户所属组分配的项目权限 if ProjectGroupPermission.objects.filter( group__in=user_obj.groups.all(), project=project, permission__codename=perm_codename ).exists(): return True return False
3. 配置授权后端
在项目settings.py中注册自定义的授权后端,可选择保留默认的全局权限后端:
AUTHENTICATION_BACKENDS = [ "django.contrib.auth.backends.ModelBackend", # 保留默认全局权限校验,不需要可删除 "your_app_name.path.to.ProjectPermissionBackend", # 替换为你自定义后端的实际路径 ]
4. 使用方式
直接调用Django原生的has_perm方法即可实现你需要的校验能力,不需要额外封装函数:
# 校验用户对project1是否有view_page权限 user.has_perm("your_app_name.view_page", obj=project1) # 直接传入Page实例也可自动关联到所属项目校验 page = Page.objects.get(id=xxx) user.has_perm("your_app_name.view_page", obj=page)
如果你不想自行实现底层逻辑,也可以直接使用成熟的第三方对象级权限库django-guardian,它已经封装了完整的按实例分配权限的能力,原生兼容Django的has_perm接口。
内容的提问来源于stack exchange,提问作者Sören Weber
相关产品推荐
相关产品推荐

