基于角色权限管理:rbac设计分析以及具体细节
权限管理---设计分析以及具体细节
说起权限我们大家都知道,不一样的角色会有不一样的权限。
比如就像学生管理系统一样,管理员,老师,学生之间的权限都是不一样的,那么展示的页面也是不一样的。
所以,我们现在来看看具体操作。
目标:生成一个独立的组件,到哪都能用!(是不是很厉害)
步骤
一、先创建一个项目,建立一个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设计分析以及具体细节的更多相关文章
- 基于角色权限管理:rbac具体代码实现
权限管理 创建一个rbac和app的应用,这个rbac主要是用来存放权限的,全称叫做基于角色权限控制 一.先看配置文件合适不,给创建的rbac在配置文件里面设置一下 找到INSTALLED_APPS= ...
- rbac(基于角色权限控制)-------权限管理
权限管理 创建一个rbac和app的应用,这个rbac主要是用来存放权限的,全称叫做基于角色权限控制 一.先看配置文件合适不,给创建的rbac在配置文件里面设置一下 找到INSTALLED_APPS= ...
- devops-jenkins基于角色的权限管理RBAC
一. devops-jenkins基于角色的权限管理RBAC 1 安装角色的rbac角色管理 1.1) 点击系统管理 1.2) 选择插件管理 1.3) 选择可选插件,输入role搜索 1.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 ...
- 【基于url权限管理 shiro(一)】--基础
只要有用户参与的系统一般都要有权限管理,权限管理实现对用户访问系统的控制,按照安全规则或者安全策略控制用户可以访问而且只能访问自己被授权的资源.权限管理包括用户认证和授权两部分. 用户认证 1.概 ...
- RDIFramework.NET ━ 9.9 角色权限管理 ━ Web部分
RDIFramework.NET ━ .NET快速信息化系统开发框架 9.9 角色权限管理 -Web部分 角色权限管理模块主要是对角色的相应权限进行集中设置.在角色权限管理模块中,管理员可以添加或移 ...
- 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 ...
- Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理
这是本人第一次写,写的不好的地方还忘包含.写这个的主要原因是想通过这个来学习下EF的CodeFirst模式,本来也想用AngularJs来玩玩的,但是自己只会普通的绑定,对指令这些不是很熟悉,所以就基 ...
- Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理10
今天把用户的菜单显示和页面的按钮显示都做好了,下面先来个效果图 接下来说下我实现的方法: 首先我在每个方法前面都加了这个属性, /// <summary> /// 表示当前Action请求 ...
随机推荐
- (2)struts2配置祥解
struts工作流程 反射 : 1.构造对象使用构造器 //类似为Servlet public class AddAction { public AddAction(){ System.out.pri ...
- sublime 3好用快捷键
sublime 3好用快捷键 自己常用 删除行 [ { "keys": ["ctrl+shift+d"], "command": " ...
- python学习笔记:第五天( 字典)
Python3 字典 字典是另一种可变容器模型,且可存储任意类型对象. 字典的每个键值(key=>value)对用冒号(:)分割,每个对之间用逗号(,)分割,整个字典包括在花括号({})中 ,格 ...
- 「洛谷 P1801」黑匣子
好像很久没有更过博客了,因为博主这几周很忙.其实是在搞颓. 题意很难懂,所以就不重复了.其实是懒. 一眼看上去这是个 \(Splay\) 裸题,直接插入一个数,查询区间第 \(K\) 大,但是这样太不 ...
- POJ3468 A Simple Problem with Integers(数状数组||区间修改的RMQ问题)
You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of op ...
- MySQL_杭州拱墅区、西湖区近9-11月销售过的产品_20161125
需求:杭州拱墅区.西湖区近9-11月销售过的产品 这个SQL如果对数据表熟悉的话可以一步到位,为了看的更清楚,时间间隔在3个月产品数量也不是很多,采取先找明细再进行汇总. 一.第一种写法 分步骤的写S ...
- ubuntu关闭cups服务
本人使用的ubuntu10.10每次开机时使用nmap扫描127.0.0.1的时候总是能发现一个631端口开启,在/etc/services找到 631端口是网络打印机服务,但对于我一个普通用户来说这 ...
- 【C++基础】重载,覆盖,隐藏
函数签名的概念 函数签名主要包括1.函数名:2.参数列表(参数的个数.数据类型和顺序):但是注意,C++官方定义中函数签名不包括返回值!! 1.重载 函数重载是指在同一作用域内,可以有一组具有相同函数 ...
- poj3784Running Median——堆维护中间值
题目:http://poj.org/problem?id=3784 将较小的数放入大根堆,较大的数放入小根堆,控制较小数堆大小比较大数堆小1,则较大数堆堆顶即为中位数. 代码如下: #include& ...
- Mysql常用命令行大全(四)外键及其它
表构成 mysql> show tables; +----------------------+| Tables_in_WebComplie |+----------------------+| ...