如何在django-river中实现对象级特定权限控制
对象级审批权限管控完全可以在django-river框架内实现,不需要替换框架,以下是两种经过验证的落地方案:
方案1:使用框架原生审批前钩子(推荐)
django-river为每个流转节点提供了完整的生命周期钩子,其中before_approve钩子会在审批操作执行前触发,入参包含当前操作人、待审批业务对象、当前流转节点实例,你可以在钩子中编写任意自定义校验逻辑,返回False时框架会直接拦截审批请求,返回权限错误。
示例代码:
# 在你的app下新建river_hooks.py,记得在app.py的ready方法中导入该文件确保钩子注册生效 from river.handlers import Handler from river.models import TransitionApproval def validate_object_level_approval_perm(user, obj, transition_approval, **kwargs): # 定位到需要做对象级校验的流转节点,例:草稿→已发布的审批节点 if ( transition_approval.transition.source.slug == "draft" and transition_approval.transition.destination.slug == "published" ): # 编写自定义判断逻辑:例如经理角色仅可审批分类为fiction的博客 is_manager = user.groups.filter(name="经理").exists() is_fiction_post = getattr(obj, "category", "") == "fiction" return is_manager and is_fiction_post # 其余节点走默认校验逻辑 return True # 注册钩子到审批前事件 Handler.register( validate_object_level_approval_perm, TransitionApproval, hook="before_approve" )
记得在app的AppConfig.ready()方法中导入这个钩子文件,否则注册不会生效:
# app.py from django.apps import AppConfig class BlogConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "blog" def ready(self): from . import river_hooks # noqa
这个方案侵入性极低,不需要修改框架源码,也不需要改动原有权限配置,适合只有部分节点需要做细粒度权限控制的场景。
方案2:自定义权限校验后端
如果你的全流程都需要统一接入对象级权限逻辑,可以替换django-river默认的权限校验后端,直接在权限判断层加入对象级校验规则。
首先自定义后端类:
# 你的app/backends.py from river.backends import DefaultRiverBackend class ObjectPermRiverBackend(DefaultRiverBackend): def has_approval_permission(self, user, transition_approval, obj): # 先执行框架默认的全局权限、用户组校验 has_base_perm = super().has_approval_permission(user, transition_approval, obj) if not has_base_perm: return False # 加入对象级权限判断逻辑 perm_code = transition_approval.meta.permission.codename if perm_code == "approve_draft": return user.groups.filter(name="经理").exists() and obj.category == "fiction" return True
然后在项目的settings.py中指定自定义后端:
RIVER_BACKEND = "blog.backends.ObjectPermRiverBackend"
这个方案适合全局统一管控对象级权限的场景,不需要为每个节点单独注册钩子。
你之前尝试重写User.has_perm()的方案不生效,是因为django-river的权限校验链路没有调用Django原生的对象级权限判断方法,而是直接拉取用户的全局权限列表做匹配,你写在has_perm里的对象级逻辑根本不会被触发,不需要在这个方向继续浪费时间。
另外需要注意:框架默认的待审批列表查询不会自动应用你写的对象级权限规则,你在开发待审批列表接口时,需要在查询层额外加上你的业务过滤条件,避免把用户无权审批的对象展示在列表中。
django-river本身的扩展能力完全可以覆盖对象级审批管控的场景,不存在不适用的问题,之前的卡点只是没有对接框架预留的扩展点而已。
内容的提问来源于stack exchange,提问作者Basel

