Skip to content

RBAC权限

采用基于角色的访问控制(RBAC)模型,通过用户-角色-菜单三层关系实现细粒度的权限管理。权限控制贯穿前后端:后端通过 PermissionRequired 混入类校验(middleware/permission_middleware.py),前端通过 v-perm 指令控制按钮显隐。

权限模型

用户(User) --N:N-- 角色(Role) --N:N-- 菜单(Menu)
 |
 type=0: 菜单(页面路由)
 type=1: 节点(权限按钮)

数据库表关系:

关联表说明
django_user_role用户-角色关联表
django_role_menu角色-菜单关联表
django_menu菜单表(含权限节点)

权限节点格式

权限节点采用 sys:module:action 三段式命名:

sys:user:list      用户列表
sys:user:add       用户新增
sys:user:update    用户编辑
sys:user:delete    用户删除
sys:user:resetPwd  重置密码
sys:role:list      角色列表
sys:role:add       角色新增
sys:menu:list      菜单列表
sys:dept:list      部门列表
sys:level:list     职级列表
sys:position:list  岗位列表

后端权限校验

PermissionRequired 混入类

middleware/permission_middleware.py 中的 PermissionRequired 混入类用于基于类的视图权限校验:

python
from middleware.permission_middleware import PermissionRequired

@method_decorator(check_login, name="get")
class UserPageView(PermissionRequired, View):
    permission_required = ("sys:user:page",)

    def get(self, request):
        result = services.get_user_page(request)
        return result

校验逻辑(完整实现):

python
# middleware/permission_middleware.py
from django.contrib.auth.mixins import PermissionRequiredMixin

class PermissionRequired(PermissionRequiredMixin):
    def has_permission(self):
        permissions = self.get_permission_required()
        user_id = get_user_id(self.request)

        # 超级管理员自动放行
        if user_id and user_id != 1:
            from application.menu import services
            permission_list = services.get_user_permissions(user_id)

            for permission in permissions:
                if permission not in permission_list:
                    return False

        return True

    def handle_no_permission(self):
        return R.failed("暂无操作权限", 401)

管理员免检

用户ID为1的管理员账号(admin)自动跳过所有权限校验,拥有全部权限。

权限数据查询

权限列表通过角色-菜单关联查询:

python
# application/menu/services.py
def get_user_permissions(user_id):
    """获取用户的权限节点列表"""
    if user_id == 1:
        # 超管拥有全部权限
        menu_list = Menu.objects.filter(
            type=1, is_delete=False
        )
    else:
        # 通过 user -> role -> menu 关联查询
        menu_list = Menu.objects.filter(
            type=1,
            is_delete=False,
            status=0,
            rolemenu__role__userrole__user_id=user_id,
            rolemenu__role__is_delete=False,
        ).distinct()

    return [item.permission for item in menu_list]

前端权限控制

v-perm 指令

前端使用自定义 v-perm 指令控制按钮显隐:

html
<!-- 只有拥有 sys:user:add 权限的用户才能看到此按钮 -->
<el-button v-perm="'sys:user:add'" type="primary">新增</el-button>

<!-- 多个权限,满足其一即可 -->
<el-button v-perm="['sys:user:update', 'sys:user:delete']">操作</el-button>

路由守卫

前端路由守卫根据用户菜单权限动态生成路由,无权限的页面不会出现在导航菜单中。

总结

RBAC 权限方案具备以下特点:

1. 三层模型:用户-角色-菜单,支持灵活的角色分配
2. 节点权限:sys:module:action 格式,细粒度控制每个操作
3. 前后端统一:后端 PermissionRequired + 前端 v-perm 指令
4. 管理员免检:userId=1 自动跳过权限校验
5. Django 原生:基于 Django PermissionRequiredMixin 扩展
6. 菜单路由:type=0 菜单生成前端路由,type=1 节点控制按钮权限

小蚂蚁云团队 · 提供技术支持