摘要:本文介绍了如何使用Django框架搭建一个灵活可扩展的权限管理系统,通过结合RABC模型,为Web应用提供精细化的用户权限管理。通过本文的设计,用户可以轻松定义角色和权限,并将其应用于Web应用的各个模块,实现访问控制和数据权限的精确控制。
一、RABC是什么
RBAC,全称为 Role-Based Access Control,即基于角色的访问控制。其核心要义在于将系统中的权限与角色紧密关联,而非直接与用户挂钩。
二、定义菜单模型
菜单模型用于存储需要权限管控的菜单项,并通过parent
字段定义父子菜单关系。菜单模型使用了MPTT
(Modified Preorder Tree Traversal)结构,能够高效地处理菜单的层级关系并支持树形结构的排序和管理。
from django.contrib.auth.models import AbstractUser, Group, Permission
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
class Menu(MPTTModel):
name = models.CharField(max_length=255, verbose_name="菜单名称") # 菜单名称
url_name = models.CharField(max_length=255, blank=True, null=True, verbose_name="URL 名称") # URL 名称
url = models.CharField(max_length=255, blank=True, null=True, verbose_name="URL")
parent = TreeForeignKey(
'self',
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name='children',
verbose_name="父菜单"
) # 父菜单
order = models.PositiveIntegerField(default=0, verbose_name="显示顺序") # 显示顺序
is_visible = models.BooleanField(default=True, verbose_name="是否可见") # 是否显示
class MPTTMeta:
order_insertion_by = ['order'] # 按顺序排序
class Meta:
verbose_name = "菜单管理"
verbose_name_plural = verbose_name
def __str__(self):
return self.name
三、定义角色模型
角色模型用于定义系统中的角色及其对应的权限。每个角色可以关联多个菜单权限和系统权限,用户通过角色获取相应的访问权限。
class Role(models.Model):
name = models.CharField(max_length=255, unique=True, verbose_name="角色名称") # 角色名称
menus = models.ManyToManyField(Menu, blank=True, related_name="roles", verbose_name="菜单权限") # 角色关联菜单
permissions = models.ManyToManyField(Permission, blank=True, related_name="roles", verbose_name="角色权限") # 角色关联权限
class Meta:
verbose_name = "角色管理"
verbose_name_plural = verbose_name
def __str__(self):
return self.name
四、定义用户模型
用户模型继承自Django的AbstractUser
,并扩展了用户与角色、权限的多对多关系。除了用户名、密码等基本字段外,还支持角色的关联管理以及自定义的用户权限。
class User(AbstractUser):
username = models.CharField("用户名", max_length=30, unique=True)
password = models.CharField("密码", max_length=128) # Django 使用加密后的密码,长度较长
roles = models.ManyToManyField(Role, related_name='users', blank=True) # 用户关联角色
created_time = models.DateTimeField('创建时间', auto_now_add=True)
updated_time = models.DateTimeField('更新时间', auto_now=True)
# 继承 AbstractUser 中的 groups 和 user_permissions,避免重复定义
groups = models.ManyToManyField(
Group,
related_name="custom_user_groups",
verbose_name="用户组",
blank=True,
)
user_permissions = models.ManyToManyField(
Permission,
related_name="custom_user_permissions",
verbose_name="用户权限",
blank=True,
)
def __str__(self):
return self.username
五、构建用户的权限菜单
此模块提供了一个通用的函数,用于根据当前登录用户的角色和权限动态构建该用户可访问的菜单树。通过该函数,开发者可以在任何需要权限控制的地方直接获取用户有权限的菜单数据。
def global_variable(request):
# 获取用户角色关联的菜单
role_menus = Menu.objects.filter(roles__users=request.user, is_visible=True).distinct()
# 获取顶级菜单(没有父菜单的菜单项)
top_level_menus = role_menus.filter(parent__isnull=True).order_by('order')
# 构造菜单树的递归函数
def build_menu_tree(menu):
children = role_menus.filter(parent=menu).order_by('order')
return {
"id": menu.id,
"name": menu.name,
"url_name": menu.url_name,
"url": menu.url,
"is_visible": menu.is_visible,
"children": [build_menu_tree(child) for child in children]
}
# 构造完整菜单树
menu_tree = [build_menu_tree(menu) for menu in top_level_menus]
return menu_tree
六、效果展示
1、维护菜单
2、给角色赋予菜单
3、给用户赋予角色
4、菜单列表展示
仅展示自己有权限的菜单