文章目录
- 一、什么是权限
- 二、RBAC模型
- 三、权限模型类设计
- 1、需要设计那些字段
- 2、特别注意
- 四、角色模型类设计
- 1、需要定义的字段有
- 2、 多对多模型类设计(重点)
- 五、用户模型类设计(前面已经设计好了)
- 六、菜单模型类设计(前面已经设计好了)
- 七、总结:上面4个表的关联关系为:如下
- 八、django的信号机制
- 1、什么是信号
- 2、代码实现
- 3、要想上面定义的信号机制生效,需要在apps.py中加载信号机制
一、什么是权限
哪些用户可以操作哪些资源就是权限,对整个后台系统进行权限控制,目的是为了避免系统的使用者因为权限控制的缺少而出现操作不当、数据泄露、流程卡住等问题
二、RBAC模型
RBAC意思是基于角色的权限控制,有别于传统模型中的直接把权限赋予账号,增加了"角色"的概念,再将角色赋予账号,提高了账号管理效率,降低了出错的概率.
权限本身有两个非常重要的要素:资源和操作
什么是操作? 增、删、改、查、还可以是其他操作
什么是资源?在我们的平台的菜单和接口
三、权限模型类设计
1、需要设计那些字段
菜单表和权限表的关系是一对多
1.name:权限名称
2.is_menu:是否为菜单,默认为菜单;如果为否,表示接口
3.method:操作,表示资源有那些操作
3.path:如果是接口,接口的url
4.desc:描述
5.menu:外键关联字段
2、特别注意
只要是choices参数的字段,如果你想要获取对应的key和value,默认获取的值是key
如果需要获取value,可以采用get_字段名_display()
print(permission.method) :获取key
print(permission.get_method_display()) :获取value
class PermissionsModel(BaseModel):
"""
权限的模型类,包含两个要素,资源(父菜单,接口)和操作
"""
method_choices = (
('POST', '增'),
('DELETE', '删'),
('PUT', '改'),
('PATCH', '改局部'),
('GET', '查'),
)
name = models.CharField('权限名称', max_length=50)
is_menu = models.BooleanField('是否为菜单', default=True) # True就是菜单,False就是接口
# 操作
method = models.CharField('操作', max_length=8, blank=True, default='', choices=method_choices)
path = models.CharField('访问的url地址', max_length=256, blank=True, null=True)
desc = models.CharField('权限的描述', max_length=512, blank=True, null=True)
menu = models.ForeignKey('MenuModel', null=True, blank=True, related_name='permissions_list',
on_delete=models.CASCADE)
def __str__(self):
return self.name
class Meta:
db_table = 't_permissions'
verbose_name = '权限表'
verbose_name_plural = verbose_name
ordering = ['id']
四、角色模型类设计
1、需要定义的字段有
角色表和权限表的关系是多对多
name:角色名称
permissions:和权限表的关联关系字段
2、 多对多模型类设计(重点)
a.多对多模型类设计的时候,外键字段可以定义在任意一个模型类中
b.多对多采用ManyToManyField
c.多对多模型类中,需要定义db_table字段选项,目的是2个表通过第三张表进行相关联
class RolesModel(BaseModel):
"""
角色模型
"""
name = models.CharField('角色名称', unique=True, max_length=50)
permissions = models.ManyToManyField('PermissionsModel', db_table='t_roles_permissions',
blank=True, verbose_name='角色的权限')
def __str__(self):
return self.name
class Meta:
db_table = 't_roles'
verbose_name = '角色表'
verbose_name_plural = verbose_name
ordering = ['id']
五、用户模型类设计(前面已经设计好了)
用户表与角色表的关系是多对多
# ERP系统的用户模型类,默认采用django自带的User类
class UserModel(AbstractUser, BaseModel):
phone = models.CharField(help_text='手机号码',
verbose_name='手机号码',
max_length=11,
unique=True,
blank=True,
null=True)
real_name = models.CharField(help_text='真实名字',
verbose_name='真实名字',
max_length=64,
blank=True,
null=True)
# 用户所有的角色
roles = models.ManyToManyField('RolesModel', db_table='t_users_roles', blank=True)
class Meta:
db_table = 't_user'
verbose_name = '系统用户表'
verbose_name_plural = verbose_name
def __str__(self):
# return self.username+":"+self.real_name
return self.username
六、菜单模型类设计(前面已经设计好了)
class MenuModel(BaseModel):
'''功能菜单的模型类'''
number = models.IntegerField(help_text='排序数字',
verbose_name='排序数字',
blank=True,
null=True)
url = models.CharField(help_text='菜单访问的url',
verbose_name='菜单访问的url',
max_length=256,
blank=True,
null=True)
name = models.CharField(help_text='菜单名字',
verbose_name='菜单名字',
unique=True,
max_length=50)
# 不会真正的把数据库中的数据删除,默认为0,如果是1当前记录删除
delete_flag = models.CharField(help_text='删除标记',
verbose_name='删除标记',
max_length=1,
default='0') # 0表示没有删除
parent = models.ForeignKey('self', #todo self:自己和自己关联
blank=True,
null=True,
related_name='children', #反向关联的属性
on_delete=models.CASCADE) #当删除的时候作级联删除
class Meta:
db_table = 't_menu'
verbose_name = '功能菜单表'
verbose_name_plural = verbose_name
ordering = ['number']
def __str__(self):
return self.name
七、总结:上面4个表的关联关系为:如下
八、django的信号机制
1、什么是信号
通俗来说,信号就是通信双方约定的一种信息通知方式,双方通过信号来确定发生了什么事情,然后决定自己应该做什么。
Django 中的信号用于在框架执行操作时解耦。当某些动作发生的时候,系统会根据信号定义的函数执行相应的操作
Django 中的信号主要包含以下三个要素:
发送者(sender):信号的发出方。
信号(signal):发送的信号本身。
接收者(receiver):信号的接收者
通知是信号中最常用的场景,比如当一个用户登录成功后,给该用户发送通知消息,或者在论坛、博客当你更新话题或者动态。就可以使用信号做信息的推送;当你的发布的动态有其他的用户给你评论的时候,也可以使用信号来通知你。
每当新增一个功能菜单的时候,初始化它对应的权限
例如:增加业务管理菜单,自动赋予它增删改查的权限
2、代码实现
import logging
from django.dispatch import receiver
from django.db.models.signals import post_save
from .models import MenuModel, PermissionsModel
logger = logging.getLogger('erp')
methods = {'POST': '新增', 'GET': '查询', 'PUT': '修改', 'DELETE': '删除'}
#函数在创建菜单的时候自动调,不是手动调
@receiver(post_save, sender=MenuModel)
def create_menus_permissions(sender, instance, created, **kwargs):
"""
sender:发送信号的人(其实就是菜单)
创建信号监控函数,信号接收者收到之后自动触发。创建菜单资源对应的权限
"""
if created:
logger.info('创建菜单资源对应的权限')
if isinstance(instance, MenuModel):
if not instance.parent: # 因为没有父菜单,所以menu就是功能模块菜单对象
permission = PermissionsModel.objects.create(name=instance.name + '的权限',
is_menu=True)
permission.menu = instance
permission.save()
else: # 当前菜单是接口
for method in methods.keys():
permission = PermissionsModel.objects.create(name=f'{instance.name}的{methods.get("method")}的权限',
is_menu=False, method=method, path=instance.url)
permission.menu=instance
permission.save()
else:
logger.warning('当前对象不是MenuModel类型,所以不需要创建对应的权限数据')
3、要想上面定义的信号机制生效,需要在apps.py中加载信号机制
当前的apps一加载,会自动执行ready函数
from django.apps import AppConfig
class ErpSystemConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'erp_system'
def ready(self):
import erp_system.signals