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

说起权限我们大家都知道,不一样的角色会有不一样的权限。

比如就像学生管理系统一样,管理员,老师,学生之间的权限都是不一样的,那么展示的页面也是不一样的。

所以,我们现在来看看具体操作。

目标:生成一个独立的组件,到哪都能用!(是不是很厉害)

步骤

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

二、表结构的设计

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

  

  2、 表结构设计      

    models中创建类:五个类,七张表
    角色表:
    用户表:
    权限表:

    权限组表:

    菜单表:

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

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

    一个菜单下面有多个组

    一个组下面有多个权限

    一个菜单下面有多个权限

 

from django.db import models

# Create your models here.
class Role(models.Model):
title = models.CharField(max_length=32,verbose_name="角色")
permissions = models.ManyToManyField(to="Permission",verbose_name="拥有权限的角色",blank=True) #权限和角色是多对多的关系 def __str__(self):
return self.title
class Meta:
verbose_name_plural = "角色表" class Permission(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):
return self.title
class Meta:
verbose_name_plural = "权限表" class UserInfo(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):
return self.name
class Meta:
verbose_name_plural = "用户表" class Group(models.Model):
title = models.CharField(max_length=32,verbose_name="组名称")
menu = models.ForeignKey(to="Menu",verbose_name="组内菜单",blank=True) #一个组下有多个菜单
def __str__(self):
return self.title
class Meta:
verbose_name_plural = "权限组" class Menu(models.Model):
caption = models.CharField(max_length=32,verbose_name="菜单")
def __str__(self):
return self.caption
class Meta:
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用的时候可以为空

当出现错误

解决办法:

python manage.py migrate --fake 废弃

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

- 先创建一个超级用户 python3 manage.py createsuperuser
    - 用户名 root
    - 密码 root1234
    - 在admin.py 中
       from rbac import models
       admin.site.register(models.Permission)
       admin.site.register(models.Role)
       admin.site.register(models.UserInfo)
      这样的话上去的是英文的,如果你想让中文显示就在类中加一个类
       class Meta:
       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、要设置表名单

2、必须继承MiddlewareMixin这个类

class MiddlewareMixin(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 not response:
response = self.get_response(request)
if hasattr(self, 'process_response'):
response = self.process_response(request, response)
return response

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

views.py

def userinfo(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中定义一个类
class BasePagePermission(object):
def __init__(self,code_list):
self.code_list = code_list
def has_add(self):
if "add" in self.code_list:
return True
def has_del(self):
if "del" in self.code_list:
return True
def has_edit(self):
if "edit" in self.code_list:
return True
实例化: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就代表可以作为菜单

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

menu_list = []
for item in permission_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}
]
}, }

八、实现

见下篇

基于角色权限管理:rbac设计分析以及具体细节的更多相关文章

  1. 基于角色权限管理:rbac具体代码实现

    权限管理 创建一个rbac和app的应用,这个rbac主要是用来存放权限的,全称叫做基于角色权限控制 一.先看配置文件合适不,给创建的rbac在配置文件里面设置一下 找到INSTALLED_APPS= ...

  2. rbac(基于角色权限控制)-------权限管理

    权限管理 创建一个rbac和app的应用,这个rbac主要是用来存放权限的,全称叫做基于角色权限控制 一.先看配置文件合适不,给创建的rbac在配置文件里面设置一下 找到INSTALLED_APPS= ...

  3. devops-jenkins基于角色的权限管理RBAC

    一. devops-jenkins基于角色的权限管理RBAC 1 安装角色的rbac角色管理  1.1) 点击系统管理 1.2) 选择插件管理 1.3) 选择可选插件,输入role搜索 1.4) 选择 ...

  4. Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架

    Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...

  5. 【基于url权限管理 shiro(一)】--基础

    只要有用户参与的系统一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源.权限管理包括用户认证和授权两部分.   用户认证 1.概 ...

  6. RDIFramework.NET ━ 9.9 角色权限管理 ━ Web部分

    RDIFramework.NET ━ .NET快速信息化系统开发框架 9.9  角色权限管理 -Web部分 角色权限管理模块主要是对角色的相应权限进行集中设置.在角色权限管理模块中,管理员可以添加或移 ...

  7. Asp.Net Core 2.0 项目实战(3)NCMVC角色权限管理前端UI预览及下载

    Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...

  8. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理

    这是本人第一次写,写的不好的地方还忘包含.写这个的主要原因是想通过这个来学习下EF的CodeFirst模式,本来也想用AngularJs来玩玩的,但是自己只会普通的绑定,对指令这些不是很熟悉,所以就基 ...

  9. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理10

    今天把用户的菜单显示和页面的按钮显示都做好了,下面先来个效果图 接下来说下我实现的方法: 首先我在每个方法前面都加了这个属性, /// <summary> /// 表示当前Action请求 ...

随机推荐

  1. joomla搬家之后打不开 首页404错误

    joomla 安装好之后, 网站打不开,首页404错误,后台能够正常访问,数据库连接正常.应该是 nginx配置的问题.该如何修改配置呢?随便一个链接点进去都是404,找不到页面,URL的形式如下: ...

  2. BZOJ 1673 [Usaco2005 Dec]Scales 天平:dfs 启发式搜索 A*搜索

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1673 题意: 有n个砝码(n <= 1000),重量为w[i]. 你要从中选择一些砝 ...

  3. ORA-21561: OID generation failed

    ORA-21561: OID generation failed 从AIX机器上连Linux上的Oracle数据库时报ORA-21561: OID generation failed错误.不是因为AI ...

  4. SqL注入攻击实践

    研究缓冲区溢出的原理,至少针对两种数据库进行差异化研究 缓冲区溢出原理 缓冲区溢出是指当计算机程序向缓冲区内填充的数据位数超过了缓冲区本身的容量.溢出的数据覆盖在合法数据上.理想情况是,程序检查数据长 ...

  5. navicat 关于orcale新建表空间,用户和权限分配

    图文教程,直观, 上面连接数据库 下面创建表空间 建表空间的设置 表空间名的设置 新建用户 填写用户名,选择默认表空间 成员属性德设置,这里因为是自己用,所以选择最大权限,其他的权限这是需要专业的了 ...

  6. arm裸机程序启动流程

    arm裸机程序启动流程 1373 Linux系统的引导: 一个SOC拿过来,它是有内部BROM和SRAM的,这个BROM中会固化芯片厂商的最初引导代码,我们叫它RBL(ROM boot loader) ...

  7. websocket之二:WebSocket编程入门

    一.WebSocket客户端 websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信.在websocket中有两个方法: 1.send() 向远程服务 ...

  8. win7 64位搭建Mantis 缺陷管理系统(2)

    建立Bug数据库 1. 右键Windows托盘的图标,选择“Local Web”,(或者在IE地址中输入“http://127.0.0.1/”)可看到如下页面: 2. 点击选择“mantis”,进入页 ...

  9. AngularJs(Part 2)

    I am still tired to translate these into Chinese. but who cares? i write these posts just for myself ...

  10. HRBUST - 1214 NOIP2000提高组 方格取数(多线程dp)

    方格取数 设有N*N的方格图(N<=10),我们将其中的某些方格中填入正整数,而其他的方格中则放人数字0.如下图所示(见样例 ,黄色和蓝色分别为两次走的路线,其中绿色的格子为黄色和蓝色共同走过的 ...