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

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

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

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

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

步骤

一、先创建一个项目,建立一个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. laravel基础课程---10、数据库基本操作(如何使用数据库)

    laravel基础课程---10.数据库基本操作(如何使用数据库) 一.总结 一句话总结: 1.链接数据库:.env环境配置里面 2.执行数据库操作:DB::table('users')->up ...

  2. jsp九大内置对象和其作用详解

    jsp九大内置对象和其作用详解 JSP中一共预先定义了9个这样的对象,分别为:request.response.session.application.out.pagecontext.config.p ...

  3. 手机移动端网站开发流程HTML5

    手机移动端网站开发流程HTML5 最近一直在研究移动手机网站的开发,发现做手机网站没有想象中的那么难.为什么会这么说呢?我们试想下:我们连传统的PC网站都会做,难道连一个小小的手机网站难道都搞不定吗? ...

  4. 分享知识-快乐自己:intellij Idea报错Could not autowire. No beans of...

    intellig idea 使用@Resource或者@Autowire报错,出现红色波浪线: 虽然不影响使用,但是看着很不爽,所以还是解决了下: 报错提示: Could not autowire. ...

  5. noip模拟赛 #2

    万年rk2 我写挂大家都挂但是有人比我挂的少 我好不容易卡一波常数然后有人ak ... T1.不想写,等会放链接 T2 给一个方阵,每个地方有一个权值,把它划成两块,不能往回拐弯,求两块极差较大的那个 ...

  6. Python手记

    字符串的拼接 1.“+”,如果是字符和数字相连,要使用str()函数对于数字进行字符转化: 2.join() 3.",",链接的两个字符串之间用空格做关联 4.占位符 tmp += ...

  7. Tomcat加载servlet类文件

    问题1:tomcat什么时候加载servlet? 有两种情况 一种是启动时加载 一种是请求时加载 第一种是在web.xml中的<servlet>节点下增加类似:<load-on-st ...

  8. Java 核心读书笔记 第11章

    1. 异常 用户希望在出现错误时,程序能够采用一些理智的行为. 如果由于出现错误而使得某些操作无法完成,程序应该:  返回到一种安全状态,并能够进行一些其他的命令: 或者:允许用于保存所有操作的结果, ...

  9. java基础之框架篇(1)

    框架基础反射:反射是Java开发的一类动态相关机制.因为本身Java语言并不是一款动态语言,如果我们想要得到程序动态的效果,因此便引入了反射机制这一概念. 问题:Java中创建实例化对象有哪些方式? ...

  10. Python 查看本机WiFi密码

    http://www.lijiejie.com/python-get-all-saved-wifi-passwords/ 很早以前我写过一个,丢了.  今天偶然看到这篇文章 , 也是很久以前写的,他用 ...