【Dv3Admin】Django一键配置权限规则

源码中的角色---菜单---按钮---字段权限控制,往往是后台系统中最容易被忽略、却最容易出问题的部分。一旦权限粒度设计不清晰,就会出现按钮越权、字段泄露、前端渲染混乱等一系列连锁问题,这类问题通常并非单点错误,而是接口设计与数据组织方式叠加后的结果。

本文围绕一个实际存在的接口方法,完整拆解"角色---菜单---按钮---字段"这一权限聚合接口的实现方式,重点聚焦参数设计、查询链路与返回结构,理清数据是如何在一次请求中被组织并下发,为后续权限渲染与前端控制提供稳定基础。

文章目录

需求解析

该接口位于基于 Django REST Framework 的权限管理模块中,运行在已接入鉴权体系的后台服务内,通过自定义 ViewSet 暴露只读接口,用于权限配置与回显场景。
请求 get_role_menu_btn_field
解析 menuId / select
查询 MenuButton
按业务模式过滤按钮
序列化按钮权限
查询 MenuField
序列化字段权限
聚合返回数据

该界面用于角色权限配置场景,按钮与字段权限通过该接口进行回显与勾选。

功能实现

定位角色菜单按钮字段聚合接口

该方法定义在 RoleMenuButtonPermissionViewSet 中,作用是一次性返回某个菜单下可用的按钮权限与字段权限,避免前端拆分多次请求导致状态难以同步。

python 复制代码
class RoleMenuButtonPermissionViewSet(CustomModelViewSet):

	......

    @action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
    def get_role_menu_btn_field(self, request):
        """
        获取 角色-菜单-按钮-列字段
        :param request:
        :return:
        """

这一层使用 @action 装饰器暴露自定义接口,并通过 IsAuthenticated 保证只有登录态可访问,否则会导致权限配置数据被匿名获取。

解析请求参数与业务选择模式

接口通过 query_params 接收前端传入的菜单标识与业务模式,用于控制按钮筛选范围。

python 复制代码
        params = request.query_params
        menuId = params.get('menuId', None)
        select = params.get('select', None)
        select_dict = {
            "快速查询": ['查询', '详情'],
            "标准业务": ['查询', '详情', '新增', '编辑', '删除', '更新']
        }

这里将业务模式与按钮名称做成映射关系,避免前端直接拼接按钮名称条件,否则会导致筛选规则分散在多处,后期维护成本上升。

构建菜单按钮查询条件

按钮数据基于菜单进行过滤,同时在存在业务模式参数时进行名称模糊匹配。

python 复制代码
        menu_btn_queryset = MenuButton.objects.filter(menu_id=menuId)  # 按条件过滤 MenuButton
        if select:
            menu_btn_queryset = menu_btn_queryset.filter(
                reduce(or_, (Q(name__icontains=val) for val in select_dict[select]))
            )

reduce + or_ + Q 的组合用于动态拼接多个 OR 查询条件,使按钮筛选规则可以通过配置字典进行扩展,需要注意的是业务模式未命中时会直接抛异常,这一步不能省略参数校验,否则会导致运行期错误。

按钮数据序列化并绑定请求上下文

查询结果通过专用序列化器进行处理,统一输出结构。

python 复制代码
        menu_btn_serializer = RoleMenuButtonSerializer(menu_btn_queryset, many=True, request=request)

将 request 传入序列化器,通常用于字段级权限或动态字段控制,否则序列化阶段无法感知当前请求环境。

查询并序列化菜单字段权限

字段权限与按钮权限属于同一菜单维度,但模型与用途不同,因此采用独立查询与序列化。

python 复制代码
        menu_field_queryset = MenuField.objects.filter(menu_id=menuId)
        menu_field_serializer = RoleMenuFieldSerializer(menu_field_queryset, many=True, request=request)

字段权限通常用于控制表格列展示或表单可编辑性,与按钮权限解耦可以避免后期权限类型膨胀导致结构混乱。

统一返回权限聚合数据

接口最终将按钮权限与字段权限合并返回,供前端一次性消费。

python 复制代码
        return DetailResponse(data={'menu_btn': menu_btn_serializer.data, 'menu_field': menu_field_serializer.data})

这种聚合返回方式减少接口调用次数,同时保证按钮与字段权限处于同一菜单上下文,避免状态不一致问题。

完整代码如下

python 复制代码
from functools import reduce
from operator import or_
from django.db.models import Q


class RoleMenuButtonPermissionViewSet(CustomModelViewSet):

	......

    @action(methods=['GET'], detail=False, permission_classes=[IsAuthenticated])
    def get_role_menu_btn_field(self, request):
        """
        获取 角色-菜单-按钮-列字段
        :param request:
        :return:
        """
        params = request.query_params
        menuId = params.get('menuId', None)
        select = params.get('select', None)
        select_dict = {
            "快速查询": ['查询', '详情'],
            "标准业务": ['查询', '详情', '新增', '编辑', '删除', '更新']
        }

        menu_btn_queryset = MenuButton.objects.filter(menu_id=menuId)  # 按条件过滤 MenuButton
        if select:
            menu_btn_queryset = menu_btn_queryset.filter(
                reduce(or_, (Q(name__icontains=val) for val in select_dict[select]))
            )
        menu_btn_serializer = RoleMenuButtonSerializer(menu_btn_queryset, many=True, request=request)
        menu_field_queryset = MenuField.objects.filter(menu_id=menuId)
        menu_field_serializer = RoleMenuFieldSerializer(menu_field_queryset, many=True, request=request)
        return DetailResponse(data={'menu_btn': menu_btn_serializer.data, 'menu_field': menu_field_serializer.data})

总结

该接口的核心设计点在于围绕菜单维度,将按钮权限与字段权限进行聚合输出,通过业务模式参数控制按钮筛选范围,使权限配置具备可扩展性与可维护性,同时避免前端承担过多筛选逻辑。当前实现中对参数合法性的依赖较强,业务模式未命中时缺乏防御性处理,后期可通过白名单校验或默认策略兜底;如果进行重写,可考虑将按钮筛选规则抽象为配置表或策略类,降低 View 层复杂度。

这一实现方式在源码层面形成了一条清晰的权限数据下发链路,既保证了接口职责单一,又为前端权限渲染提供了稳定的数据基础,在多角色、多菜单系统中具备直接复用价值。

相关推荐
92year5 分钟前
我用运筹学穷举了麦当劳全菜单:30 块预算,怎么吃到全局最优?
python·agent·mcp
用户7624117567055 分钟前
第三章 流程控制语句
python
东莞市云毅网络有限公司18 分钟前
结构化标注缺失怎么查:JSON-LD抽取与每日巡检脚本实现
python·sqlite·自动化运维·geo·数据监测
2601_9629666432 分钟前
数学与应用数学专业准备风险管理岗,2027届秋招金融知识和工具技能怎么补?
python·sql
码流子39 分钟前
02-易迁信创兼容引擎
大数据·数据库·python
kimnoic44 分钟前
Python常见模块及其用法示例详解
开发语言·python
databook1 小时前
Scikit-Learn实战:5步搞定PCA降维
python·机器学习·scikit-learn
溪语流沙1 小时前
【Web全栈进阶】JWT无状态认证:签发、校验、刷新
前端·git·python·github
reasonsummer1 小时前
【办公类-112-08】20261009园园通信息合并配学号拆班(数据更新,用年月日期区分版本)
python
阿狗童鞋1 小时前
Python爬虫进阶实战指南
开发语言·爬虫·python