权限管理--设计分析以及具体细节

摘要:
说起权限我们大家都知道,不一样的角色会有不一样的权限。比如就像学生管理系统一样,管理员,老师,学生之间的权限都是不一样的,那么展示的页面也是不一样的。所以,我们现在来看看具体操作。

说起权限我们大家都知道,不一样的角色会有不一样的权限。比如就像学生管理系统一样,管理员,老师,学生之间的权限都是不一样的,那么展示的页面也是不一样的。所以,我们现在来看看具体操作。

目标:生成一个独立的组件,到哪都能用

一、先创建一个 项目,建一个app01和rbac的应用

二、表结构设计

1、先看配置文件合适不,给创建的rbac在配置文件里面设置一下
找到INSTALLED_APPS=['rbac']

权限管理--设计分析以及具体细节第1张

配置静态文件

权限管理--设计分析以及具体细节第2张

2、设计表结构
models中创建类:五个类,七张表
角色表:
用户表:
权限表:

权限组表:

菜单表:

角色表和权限表是多对多的关系(一个角色可以有多个权限,一个权限可以对应多个角色)
用户表和角色表是多对多的关系(一个用户可以有多个角色,一个角色有多个用户)

所以有会多生成两张关系表

一个菜单下面有多个组

一个组下面有多个菜单

一个菜单下面有多个权限

权限管理--设计分析以及具体细节第3张

复制代码
from django.db importmodels

#Create your models here.
classRole(models.Model):
    title = models.CharField(max_length=32,verbose_name="角色")
    permissions = models.ManyToManyField(to="Permission",verbose_name="拥有权限的角色",blank=True)  #权限和角色是多对多的关系

    def __str__(self):
        returnself.title
    classMeta:
        verbose_name_plural = "角色表"

classPermission(models.Model):
    title = models.CharField(max_length=32,verbose_name="权限名")
    url = models.CharField(max_length=32,verbose_name="带正则的url")
    codes = models.CharField(max_length=32,verbose_name="代码")
    group = models.ForeignKey(to="Group",verbose_name="所属组",blank=True)  #组和权限是一对多的关系,一个组有多个权限
    menu_gp = models.ForeignKey(to='Permission',related_name='aaa',null=True,blank=True,verbose_name="组内菜单")
    def __str__(self):
        returnself.title
    classMeta:
        verbose_name_plural = "权限表"

classUserInfo(models.Model):
    name = models.CharField(max_length=32,verbose_name="姓名")
    password = models.CharField(max_length=64,verbose_name="密码")
    email = models.CharField(max_length=32,verbose_name="邮箱")
    roles = models.ManyToManyField(to="Role",blank=True)  #用户和角色是多对多的关系
    def __str__(self):
        returnself.name
    classMeta:
        verbose_name_plural = "用户表"

classGroup(models.Model):
    title = models.CharField(max_length=32,verbose_name="组名称")
    menu = models.ForeignKey(to="Menu",verbose_name="组内菜单",blank=True)  #一个组下有多个菜单
    def __str__(self):
        returnself.title
    classMeta:
        verbose_name_plural = "权限"

classMenu(models.Model):
    caption = models.CharField(max_length=32,verbose_name="菜单")
    def __str__(self):
        returnself.caption
    classMeta:
        verbose_name_plural = "菜单表"
复制代码

具体分析为什么要多加个code列和权限组表呢?

1、我们一般是先看到的是列表页面,在这个页面上是否显示添加,是否显示编辑,是否显示删除,都是需要判断的
有无添加权限,有无删除权限,有无编辑权限,我们可以给每一个url一个代号

复制代码
dict ={
    1:{                    代号
          /userinfo/list
       /userinfo/add/add
       /userinfo/del(d+)/    del 
       /userinfo/edit(d+)/edit
    }
  }
         
复制代码

不仅在列表页面需要知道他有那些权限,在其他页面也知道他有那些权限
所以上面的方案还是有点不好,那么我们采取下面的方案。将代号取出来放在一个列表里面

复制代码
dict ={
      1:{
              "codes":["list","add","del","edit"]
             urls:[
                "/userinfo/",
                "/userinfo/add"/,
                "/userinfo/del(d+)/ ",
                "/userinfo/edit(d+)/ ",
              ]    
        }
      2:{
           "codes":{"list","add","del","edit"}
            urls:[
                 "/order",
                 "/order/add"/,
                  "/order/del(d+)/ ",
                 "/order/edit(d+)/ ",
               ]    
       }
}            
复制代码

把这个字典存到session中
当你访问页面的时候我就知道你有什么权限
一个url对应一个code
多个url对应一个组

注意:
关联字段 null = True 数据库用的时候可以为空
关联字段 blank = True admin用的时候可以为空
当出现这个错误的时候

权限管理--设计分析以及具体细节第10张

解决办法

python manage.py migrate --fake 废弃

三、通过django-admin录入权限数据

复制代码
-先创建一个超级用户 python3 manage.py createsuperuser
    -用户名 root
    -密码 zhy123456
    -在admin.py 中
        from rbac importmodels
        admin.site.register(models.Permission)
        admin.site.register(models.Role)
        admin.site.register(models.UserInfo)
      这样的话上去的是英文的,如果你想让中文显示就在类中加一个类
        classMeta:
           verbose_name_plural = "权限表"
      - 当你给关联字段录入数据的时候会有错误提示,那么在类中你的那个关联字段在加一个属性blank =True 可以为空
      permissions = models.ManyToManyField(to="Permission",verbose_name="具有的所有权限", blank=True)
复制代码

四、编写登录

1.编写登录
2.如果用户验证成功就设置session
3.先查出当前用户的所有的权限
4.从这些权限中找到所有的url,吧这些url放到session中
这些都是在rbac里面的操作,如果我们做一些复杂的操作,可能会有好多的代码
我们写rbac的目的是做成一个公共的组件,为了让别人省事
我们在创建一个server的文件夹,里面创建一个init_permission的py文件。

结构化数据:方便以后做操作。。。

复制代码
dict ={
      1:{
              "codes":["list","add","del","edit"]
             urls:[
                "/userinfo/",
                "/userinfo/add"/,
                "/userinfo/del(d+)/ ",
                "/userinfo/edit(d+)/ ",
              ]    
        }
      2:{
           "codes":{"list","add","del","edit"}
            urls:[
                 "/order",
                 "/order/add"/,
                  "/order/del(d+)/ ",
                 "/order/edit(d+)/ ",
               ]    
       }
}            
复制代码

5.拿到用户请求的url去session里面做验证
获取当前请求的url
获取session中保存当前用户的权限
然后开始验证
如果匹配成功就有权访问
如果匹配不成功就无权访问
用re去匹配的时候,re.match(/userinfo/,/userinfo/add) #都能匹配到
那么要记得在匹配正则的时候加个起始符和终止符regex = "^{0}$".format(url)
def login(request):
.....
设置session
def index(request):
....
获取session
def userinfo(request):
获取session
这样如果有好多个函数,就的重复好多代码,我们可以用中间件来处理
中间件和装饰器的区别:
中间件用来做批量处理
如果函数不多的话可以用加装饰器的方法

五、中间件:获取session,并且当用户匹配成功的时候,先把code保存在request中,方便以后判断

1、记得要配置白名单

权限管理--设计分析以及具体细节第15张

2、必须继承MiddlewareMixin这个类

复制代码
classMiddlewareMixin(object):
    def __init__(self, get_response=None):
        self.get_response =get_response
        super(MiddlewareMixin, self).__init__()

    def __call__(self, request):
        response =None
        if hasattr(self, 'process_request'):
            response =self.process_request(request)
        if notresponse:
            response =self.get_response(request)
        if hasattr(self, 'process_response'):
            response =self.process_response(request, response)
        return response
复制代码

六、设计权限管理-----问题:在访问列表页面时,是否需要判断有无添加权限、有无删除权限、有无编辑权限。

views

复制代码
defuserinfo(request):
    #方式一
    #Page_permission = request.permission_code_list
    #方式二:实例化
    page_permission =BasePagePermission(request.permission_code_list)
    print("page_permission",request.permission_code_list)
    data_list =[
        {"id":1,"name":"xxx1"},
        {"id":2,"name":"xxx2"},
        {"id":3,"name":"xxx3"},
        {"id":4,"name":"xxx4"},
        {"id":5,"name":"xxx5"},
    ]
    return render(request,"userinfo.html",{"data_list":data_list,"page_permission":page_permission})

    
复制代码

在模板userinfo.html中:两种使用方式

方式一:

复制代码
<table>{% if "add" in Page_permission %}
        <a href="#">添加</a>{% endif %}
    {% for row in data_list %}
         <tr>
            <td>{{ row.id }}</td>
            <td>{{ row.name }}</td>{% if "edit" in Page_permission %}
                <td><a href="#">编辑</a></td>{% endif %}
           {% if "del" in Page_permission %}
                 <td>{<a href="#">删除</a></td>{% endif %}
        </tr>{% endfor %}
</table>
复制代码

如果不想像上面一样每个都判断,那么还有第二种方法,

方式二:

复制代码
吧permission_code_list处理一下
在views中定义一个类
classBasePagePermission(object):
    def __init__(self,code_list):
        self.code_list =code_list
    defhas_add(self):
        if "add" inself.code_list:
            returnTrue
    defhas_del(self):
        if "del" inself.code_list:
            returnTrue
    defhas_edit(self):
        if "edit" inself.code_list:
            returnTrue
实例化:page_permission =BasePagePermission(request.permission_code_list)
在模板中
<table>{% if page_permission.has_add %}
        <a href="#">添加</a>{% endif %}
    {% for row in data_list %}
         <tr>
            <td>{{ row.id }}</td>
            <td>{{ row.name }}</td>{% if page_permission.has_edit %}
                <td><a href="#">编辑</a></td>{% endif %}
           {% if page_permission.has_del %}
                 <td>{<a href="#">删除</a></td>{% endif %}
        </tr>{% endfor %}
</table>
复制代码

七、设计菜单管理-----问题:1、如何生成菜单

2、怎么让这些菜单分级显示并且如果当前访问的url权限默认展开如果是组内菜单就加粗或者变红

3、非菜单url,默认选中原菜单。(如果你是点击用户列表进来的,那么你看到页面了,如果你点击添加的时候,你的那个用户列看不见了,这就不好了。所以要设计当你点击添加按钮的时候,那个用户列表被默认选中)

菜单管理
菜单一
用户管理
权限管理
菜单二
订单管理
角色管理

分级做了菜单。这些菜单该显示什么菜单?是当前用户登录之后从数据库拿到这个用户拥有的权限,然后把权限搞成菜单

在表里面设计了一个组内菜单(自关联 ),当menu_gp_id为NULL就代表可以作为菜单

权限管理--设计分析以及具体细节第24张

1、在初始化的时候,初始化权限信息,获取权限信息并放置到session中

复制代码
 menu_list =[]
    for item inpermission_list:
        tpl ={
            "id":item["permissions__id"],
            "title":item["permissions__title"],
            "url":item["permissions__url"],
            "menu_gp_id":item["permissions__menu_gp_id"],
            "menu_id":item["permissions__group__menu_id"],
            "menu_title":item["permissions__group__menu__caption"]
        }
        menu_list.append(tpl)
    request.session[settings.PERMISSION_MENU_KEY] = menu_list
复制代码

因为是要在页面上渲染,一般我们会在视图函数的render里面加{"":变量}这样渲染,
但是还有个更好用的方法:用自定义的标签

具体操作:
1、找到app创建一个templatetags的文件夹
2、然后在里面随便创建一个文件
3、导入form django.template import Library
register = Library()

方式一:
@register.simple_tag
def menu():
return "菜单" 这里返回啥页面上就显示啥
然后在母版里面导入mnue.html
{% load rbac %}

方式二:
@register.includsion_tag("xxx.html") #这里存放的是html文件,,,@register.includsion_tag("xxx.html") 自动会读这个文件并且把返回值拿到在页面上渲染
def menu():
return "菜单" 这里返回啥页面上就显示啥
“在母版中:{%menu_html request%} request是参数,记得要加上{% load rbac %}

4、注意:
如果有两个文件夹同名,避免发生冲突:就再创建一个文件夹包起来

2、去Session中获取菜单相关信息,匹配当前URL,生成菜单

先把和菜单相关的所有字段取出来

复制代码
menu_list =[
    {'id': 1, 'title': '用户列表', 'url': '/userinfo/', 'menu_gp_id': None, 'menu_id': 2, 'menu_title': '菜单二'}, 
    {'id': 2, 'title': '添加用户', 'url': '/userinfo/add/', 'menu_gp_id': 1, 'menu_id': 2, 'menu_title': '菜单二'}, 
    {'id': 3, 'title': '删除用户', 'url': '/userinfo/del/(\d+)/', 'menu_gp_id': 1, 'menu_id': 2, 'menu_title': '菜单二'}, 
    {'id': 4, 'title': '编辑用户', 'url': '/userinfo/edit/(\d+)/', 'menu_gp_id': 1, 'menu_id': 2, 'menu_title': '菜单二'}, 
    {'id': 5, 'title': '订单列表','url': '/order/', 'menu_gp_id': None, 'menu_id': 1, 'menu_title': '菜单一'}, 
    {'id': 6, 'title': '添加订单', 'url': '/order/add/', 'menu_gp_id': 2, 'menu_id': 1, 'menu_title': '菜单一'}, 
    {'id': 7, 'title': '删除订单', 'url': '/order/del/(\d+)/', 'menu_gp_id': 2, 'menu_id': 1, 'menu_title': '菜单一'}, 
    {'id': 8, 'title': '编辑订单', 'url': '/order/edit/(\d+)/', 'menu_gp_id': 2, 'menu_id': 1, 'menu_title': '菜单一'}
]
复制代码

然后循环列表找出可以作为菜单的权限

{
    1: {'id': 1, 'title': '用户列表', 'url': '/userinfo/', 'menu_gp_id': None, 'menu_id': 2, 'menu_title': '菜单二'}, 
    5: {'id': 5, 'title': '订单列表', 'url': '/order/', 'menu_gp_id': None, 'menu_id': 1, 'menu_title': '菜单一'}
}

再次循环列表向上边的字典中添加active

{
    1: {'id': 1, 'title': '用户列表', 'url': '/userinfo/', 'menu_gp_id': None, 'menu_id': 2, 'menu_title': '菜单二', 'active': True},
    5: {'id': 5, 'title': '订单列表', 'url': '/order/', 'menu_gp_id': None, 'menu_id': 1, 'menu_title': '菜单一'}
}

结构化数据(吧上面得到的数据化成下面这样格式的,方便以后使用)

复制代码
{
    1: {
            'menu_id': 1,
            'menu_title': '菜单一',
            'active': None, 
            'children': [
                    {'title': '订单列表', 'url': '/order/', 'active': None}
                ]
            }
    2: {
        'menu_id': 2, 
        'menu_title': '菜单二', 
        'active': True,
        'children': [
                {'title': '用户列表', 'url': '/userinfo/', 'active': True}
            ]
        },
    
}
复制代码

免责声明:文章转载自《权限管理--设计分析以及具体细节》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Vim简明教程【CoolShell】实验三 UML 建模工具的安装与使用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Android ----------------- 面试题 整理 一

1. XML的解析方式都有哪些? 每一种解析方式的运行流程? 设XML为:<a>a<b>bc<c>c1</c></b></a> Dom SAXPull 2.<a>a<b>bc<c>c1</c></b></a>...

Docker从入门到放弃

  为什么要学习 docker 呢?深有体会,由于一些原因只能在他人电脑上搭建环境,明明在自己电脑上的程序跑的好好的,在他人的电脑上就是死活出错。折磨人呀!!!!!可是能怎么办,工作还得继续,曲线救国呗,折腾了一天终于搞好了,那么以后呢?想到了之前搭建靶机时候用到的docker,时间长了也忘了,准备好好梳理学习入门一波。《十分感谢大神的文章,本文基于大神的...

【原创】简单快速软件开发平台,C/S架构二次开发平台

简单快速软件开发平台,二次开发平台 二次开发平台可根据企业的需求,灵活快速搭建企业业务管理系统,充分满足企业个性化的需求。C/S系统快速开发框架为企业和个人提供快速开发能力,能快速搭建C/S架构模式的企业管理应用系统。C/S系统快速开发框架提供开发大型软件系统的底层模板,基于开发框架的VS解决方案源码,改名为自己的软件系统名称,如:MyERP,MyMES等...

iOS证书详解--转载

一、成员介绍1.    Certification(证书)证书是对电脑开发资格的认证,每个开发者帐号有一套,分为两种:1)    Developer Certification(开发证书)安装在电脑上提供权限:开发人员通过设备进行真机测试。可以生成副本供多台电脑安装;2)      Distribution Certification(发布证书)安装在电脑...

谈谈Android重打包--初语

写在前面的话仅以此系列献给喜欢我CSDN的小伙伴们 申明此文禁止转载,谢谢合作 序言 在开头说这会是一个系列,那就说明我有非常多话要说。从最简单的介绍到问题的提出。解决方式的构思以及整个系统的架构实现測试都会在这个系列里一一说明。假设你还在迷茫该怎么去深入一个问题,一点点解决,那我尽力会通过这个系列让你有一点点感悟。假设你已经一览众山小,那么请给我...

linux中apt-get使用

apt-get简介 在Ubuntu系统中,经常要用到apt-get install指令来安装软件,由于常常需要root权限来操作,所以搭配sudo食用口感更佳,apt-get指令对于安装、卸载、升级软件提供一条龙服务,对比于源码安装,实在是业界良心。 源码安装 源码安装的流程一般是三部曲: ./configure make make install...