? (Role-Based Access Control)
为什么要有权限:
区分用户的 功能
在web开发中 url代表权限
表结构:
from django.db import models
class Permission(models.Model):
url = models.CharField(max_length=32, verbose_name='权限')
title = models.CharField(max_length=32, verbose_name='标题')
class Meta:
verbose_name_plural = '权限'
verbose_name = '权限'
def __str__(self):
return self.title
class Role(models.Model):
"""
角色表
"""
name = models.CharField(max_length=32, verbose_name='名称')
permissions = models.ManyToManyField('Permission', verbose_name='角色拥有的权限', blank=True)
def __str__(self):
return self.name
class User(models.Model):
"""
用户表
"""
name = models.CharField(max_length=32, verbose_name='名称')
password = models.CharField(max_length=32, verbose_name='密码')
roles = models.ManyToManyField('Role', verbose_name='用户拥有的角色', blank=True)
def __str__(self):
return self.name
流程
录入权限信息到数据库
登录成功后保存用户的权限到session中
def login(request):
if request.method == 'POST':
user = request.POST.get('user')
pwd = request.POST.get('pwd')
obj = models.User.objects.filter(name=user, password=pwd).first()
if not obj:
return render(request, 'login.html', {'error_msg': '用户名或密码错误'})
# 登陆成果 保存权限的信息
ret = obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
'permissions__title').distinct()
# 保存权限信息
request.session[settings.PERMISSION_SESSION_KEY] = list(ret)
return redirect(reverse('customer_list'))
return render(request, 'login.html')
在setting 配置中 配置
# ################################ 权限的配置 ################################
# 权限的key
PERMISSION_SESSION_KEY = 'permissions'
# 菜单的key
PERMISSION_MENU_KEY = 'menus'
WHITE_LIST = [
r'^/login/$',
r'^/reg/$',
r'^/admin/.*',
]
中间件中对权限进行检验(白名单)
class RbacMiddleware(MiddlewareMixin):
def process_request(self, request):
# 1. 获取当前访问的URL
url = request.path_info
# 白名单
for i in settings.WHITE_LIST:
if re.match(i, url):
return
# 2. 获取当前用户的权限信息 无权限的 跳转 login
permission_list = request.session.get(settings.PERMISSION_SESSION_KEY)
if not permission_list:
return redirect(reverse('login'))
# 3. 权限的校验
for i in permission_list:
if re.match(r"^{}$".format(i['url']), url):
return
# 拒绝访问
return HttpResponse('没有访问权限')
表结构
from django.db import models
class Permission(models.Model):
"""
权限表
可做菜单的权限 is_menu=True
不可做菜单的权限 is_menu=False
"""
url = models.CharField(max_length=32, verbose_name='权限')
title = models.CharField(max_length=32, verbose_name='标题')
is_menu = models.BooleanField(default=False, verbose_name='是否是菜单')
icon = models.CharField(max_length=64, null=True, blank=True, verbose_name='图标')
class Meta:
verbose_name_plural = '权限'
verbose_name = '权限'
def __str__(self):
return self.title
class Role(models.Model):
"""
角色表
"""
name = models.CharField(max_length=32, verbose_name='名称')
permissions = models.ManyToManyField('Permission', verbose_name='角色拥有的权限', blank=True)
def __str__(self):
return self.name
class User(models.Model):
"""
用户表
"""
name = models.CharField(max_length=32, verbose_name='名称')
password = models.CharField(max_length=32, verbose_name='密码')
roles = models.ManyToManyField('Role', verbose_name='用户拥有的角色', blank=True)
def __str__(self):
return self.name
流程:
# 在 rbac app中 定义 一个文件 处理 信息的 录入
def init_permisson(request, obj):
"""
权限信息的初识化
保存权限和菜单的信息
:param request:
:param obj:
:return:
"""
ret = obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
'permissions__title',
'permissions__is_menu',
'permissions__icon',
).distinct()
# 存放权限信息
permission_list = []
# 存放菜单信息
menu_list = []
for item in ret:
# 将所有的权限信息添加到permission_list
permission_list.append({'url': item['permissions__url']})
# 把是菜单的权限信息放入到menu_list
if item.get('permissions__is_menu'):
menu_list.append({'url': item['permissions__url'], 'title': item['permissions__title'],
'icon': item['permissions__icon']})
# 保存权限信息
request.session[settings.PERMISSION_SESSION_KEY] = permission_list
# 保存菜单信息
request.session[settings.PERMISSION_MENU_KEY] = menu_list
定义 菜单的 heml 代码块 使用 inclusion_tag
html 代码 menu.html
<div class="static-menu">
{# <a href="/customer/list/" class="active">#}
{# <span class="icon-wrap"><i class="fa fa-connectdevelop"></i></span> 客户管理</a>#}
{# <a href="/payment/list/">#}
{# <span class="icon-wrap"><i class="fa fa-code-fork"></i></span> 账单管理</a>#}
{% for item in menu_list %}
<a href="{{ item.url }}" class="{{ item.class }}">
<span class="icon-wrap"><i class="fa {{ item.icon }}"></i></span> {{ item.title }}</a>
{% endfor %}
</div>
inclusion_tag
from django import template
from django.conf import settings
import re
register = template.Library()
@register.inclusion_tag('rbac/menu.html')
def menu(request):
menu_list = request.session.get(settings.PERMISSION_MENU_KEY)
for item in menu_list:
if re.match("^{}$".format(item['url']), request.path_info):
item['class'] = 'active'
break
return {'menu_list': menu_list}
定义 代码块的css 样式 menu.css
.static-menu .icon-wrap {
width: 20px;
display: inline-block;
text-align: center;
}
.static-menu a {
text-decoration: none;
padding: 8px 15px;
border-bottom: 1px solid #ccc;
color: #333;
display: block;
background: #efefef;
background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #efefef), color-stop(1, #fafafa));
background: -ms-linear-gradient(bottom, #efefef, #fafafa);
background: -moz-linear-gradient(center bottom, #efefef 0%, #fafafa 100%);
background: -o-linear-gradient(bottom, #efefef, #fafafa);
filter: progid:dximagetransform.microsoft.gradient(startColorStr='#e3e3e3', EndColorStr='#ffffff');
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa',EndColorStr='#efefef')";
box-shadow: inset 0px 1px 1px white;
}
.static-menu a:hover {
color: #2F72AB;
border-left: 2px solid #2F72AB;
}
.static-menu a.active {
color: #2F72AB;
border-left: 2px solid #2F72AB;
}
在 母版中 导入 css 样式 以及使用 inclusion_tag 返回菜单列表
<link rel="stylesheet" href="{% static 'css/menu.css' %} "/>
{% load rbac %}
{% menu request %}
表结构:
from django.db import models
# Create your models here.
class Menu(models.Model):
''' 一级菜单 '''
title = models.CharField(max_length=32)
icon = models.CharField(max_length=64, null=True, blank=True, verbose_name='图标')
def __str__(self):
return self.title
class Permission(models.Model):
'''
权限表
可以做二级菜单的权限 menu 关联 菜单表
不可以做菜单的权限 menu=null
'''
url = models.CharField(max_length=32, verbose_name='路径')
title = models.CharField(max_length=32, verbose_name='描述')
menu = models.ForeignKey('Menu', null=True, blank=True)
def __str__(self):
return self.title
class Role(models.Model):
'''
角色表 部门
'''
name = models.CharField(max_length=32, verbose_name='角色')
permissions = models.ManyToManyField('Permission', verbose_name='角色拥有的权限', blank=True)
def __str__(self):
return self.name
class User(models.Model):
'''
用户表
'''
name = models.CharField(max_length=32, verbose_name='用户名')
password = models.CharField(max_length=32, verbose_name='密码')
roles = models.ManyToManyField('Role', blank=True, verbose_name='用户拥有的角色')
def __str__(self):
return self.name
class Meta:
verbose_name_plural = '用户'
verbose_name = '用户表'
二级菜单的 数据结构
data = [{
'permissions__url': '/customer/list/',
'permissions__title': '客户列表',
'permissions__menu__title': '信息列表',
'permissions__menu__icon': 'fa-code-fork',
'permissions__menu_id': 1
},
{
'permissions__url': '/customer/list/',
'permissions__title': '用户列表',
'permissions__menu__title': '信息列表',
'permissions__menu__icon': 'fa-code-fork',
'permissions__menu_id': 1
},{
'permissions__url': '/customer/add/',
'permissions__title': '增加客户',
'permissions__menu__title': None,
'permissions__menu__icon': None,
'permissions__menu_id': None
}, {
'permissions__url': '/customer/edit/(\\d+)/',
'permissions__title': '编辑客户',
'permissions__menu__title': None,
'permissions__menu__icon': None,
'permissions__menu_id': None
}]
"""
{
1:{
'title':'信息列表',
'icnon':'fa-code-fork',
'children': [
{'title': '客户列表','url':'/customer/list/ },
{'title': '用户列表','url':'/customer/list/ }
]
}
}
"""
流程:
# 在 rbac app中 定义 一个文件 处理 信息的 录入
def init_permisson(request, obj):
"""
权限信息的初识化
保存权限和菜单的信息
:param request:
:param obj:
:return:
"""
ret = obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
'permissions__title', 'permissions__menu__title',
'permissions__menu__icon',
'permissions__menu_id',
).distinct()
print(ret)
# 存放权限信息
permission_list = []
# 存放菜单信息
menu_dict = {} VGB M,K.L/;['}.+
*6654=-908877 }0']
for item in ret:
# 将所有的权限信息添加到permission_list
permission_list.append({'url': item['permissions__url']})
# 构造菜单的数据结构
menu_id = item.get('permissions__menu_id')
# 表示当前的权限是不做菜单的权限
if not menu_id:
continue
# 可以做菜单的权限
if menu_id not in menu_dict:
menu_dict[menu_id] = {
'title': item['permissions__menu__title'], # 一级菜单标题
'icon': item['permissions__menu__icon'],
'children': [{'title': item['permissions__title'], 'url': item['permissions__url']}]
}
else:
menu_dict[menu_id]['children'].append(
{'title': item['permissions__title'], 'url': item['permissions__url']})
print(menu_dict)
# 保存权限信息
request.session[settings.PERMISSION_SESSION_KEY] = permission_list
# 保存菜单信息
request.session[settings.PERMISSION_MENU_KEY] = menu_dict
定义html代码块 及 inclusion_tag
html代码块
<div class="multi-menu">
{% for item in menu_list %}
<div class="item">
<div class="title"><i class="fa {{ item.icon }}"></i> {{ item.title }} </div>
<div class="body">
{% for child in item.children %}
<a href="{{ child.url }}">{{ child.title }}</a>
{% endfor %}
</div>
</div>
{% endfor %}
</div>
? inclusion_tag rbac.py
from django import template
from django.conf import settings
import re
register = template.Library()
@register.inclusion_tag('rbac/menu.html')
def menu(request):
menu_dict = request.session.get(settings.PERMISSION_MENU_KEY)
return {'menu_list': menu_dict.values()}
.multi-menu .item {
background-color: white;
}
.multi-menu .item > .title {
padding: 10px 5px;
border-bottom: 1px solid #dddddd;
cursor: pointer;
color: #333;
display: block;
background: #efefef;
background: -webkit-gradient(linear, left bottom, left top, color-stop(0, #efefef), color-stop(1, #fafafa));
background: -ms-linear-gradient(bottom, #efefef, #fafafa);
background: -o-linear-gradient(bottom, #efefef, #fafafa);
filter: progid:dximagetransform.microsoft.gradient(startColorStr='#e3e3e3', EndColorStr='#ffffff');
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#fafafa',EndColorStr='#efefef')";
box-shadow: inset 0 1px 1px white;
}
.multi-menu .item > .body {
border-bottom: 1px solid #dddddd;
}
.multi-menu .item > .body a {
display: block;
padding: 5px 20px;
text-decoration: none;
border-left: 2px solid transparent;
font-size: 13px;
}
.multi-menu .item > .body a:hover {
border-left: 2px solid #2F72AB;
}
.multi-menu .item > .body a.active {
border-left: 2px solid #2F72AB;
}
使用:
在 母版中 导入 css 样式 以及使用 inclusion_tag 返回菜单列表
<link rel="stylesheet" href="{% static 'css/menu.css' %} "/>
{% load rbac %}
{% menu request %}
二级菜单的 点击动画
$(function () {
$('.item .title').click(function () {
{#$(this).next().toggleClass('hide')#}
$('.item .title').siblings($(this)).slideUp(100);
$(this).next().slideDown(100);
{#展开当前 一级菜单 下的 二级菜单#}
{#$(this).next().removeClass('hide');#}
{# 关闭其他菜单 下的 二级菜单#}
{#$(this).parent().siblings().find('.body').addClass('hide');#}
})
})
给一级菜单进行排序
在model 中 添加 权重 字段
# 1.model 中 的权限表 添加 权重字段
weight = models.IntegerField(default=1, verbose_name='权重')
# 2.查询出权重 将其加入到 menu_dict 的一级菜单中
# 3. 在 inclusion_tag 中 给菜单进行排序
# 导入 OrderedDict 有序字典 因为字典是无序的 查询出的顺序不一定
from collections import OrderedDict
ordered_dict = OrderedDict()
# 给菜单进行排序
for i in sorted(menu_dict, key=lambda a: menu_dict[a]['weight'], reverse=True):
# 将 menu_dict 循环添加到 实例化的 OrderedDict() 中
ordered_dict[i] = menu_dict[i]
信息列表 # 一级菜单
? 客户列表 # 二级菜单
添加客户 # 非菜单权限
编辑客户 # 非菜单权限
财务列表
缴费列表
权限表中
menu_id : 关联的菜单
parent_id: 外键关联自己 三级菜单 ‘self’ 判断从属于那个权限
id url title menu_id parent_id
1 /list/ 客户列表 1 null
2 /add/ 添加客户 null 1
给权限表中 加入 paren 外键的字段 可以为空
paren = models.ForeignKey('self', null=True, blank=True)
获取 paren 关联的 id 也就是 父id 从属于那个权限 以及 本权限的id
permission = obj.roles.all().filter(permissions__url__isnull=False)
.values('permissions__url',
'permissions__title', 'permissions__menu__title', 'permissions__menu__font',
'permissions__menu__weight', # 权重
'permissions__menu_id',
#'permissions__weight',
'permissions__paren_id', # 关联的 归属id
'permissions__id', # 本权限的 id
).distinct()
將 id pid 存放到 permissions_list 中的每个字典中
permissions_list.append({'url': item['permissions__url'],
'id': item['permissions__id'],
'pid': item['permissions__paren_id'], }) #paren 括弧
存放 权限id 到 二级菜单的 children中
'children': [{'title': item['permissions__title'],
'url': item['permissions__url'],
'id': item['permissions__id'],
}]}
从 中间件中获取到 两个id 做判断 將 从属的 id 存放到 request 对象中
# 记录 paren 的 id 到 request 中
id, pid = i['id'], i['pid']
if pid:
# 有PID表示当前访问的权限是子权限 它有父权限 要让这个父权限展开
request.xxx = pid
else:
# 表示当前访问的权限是父权限 要让自己展开
request.xxx = id
从 inclusion_tag 中 取到 没个菜单的 children 循环 判断 从属的 id 是不是 本 权限的 id
给从属的 权限加上 显示 及 active
item['class'] = 'hide'
for child in item['children']:
# if re.match("^{}$".format(child['url']), request.path_info):
if request.xxx == child['id']:
child['class'] = 'active'
item['class'] = ''
面包屑 导航
注意 :
? 权限信息放入到session中。进行json序列化
? 字段的key 如果是数字化,会变成数字字符串
將 权限 dict 中加入 title 描述
字典中 本身就有 路径 以及 描述
permissions_dict[item['permissions__id']] = ({'url': item['permissions__url'],
'id': item['permissions__id'],
'pid': item['permissions__paren_id'],
'title': item['permissions__title']})
在 中间件中 创建 一个 面包屑的列表 存到 request 中
# 创建列表 使用 反射 添加到 request 中 名字在 settings 中配置
setattr(request, setting.BREADCRUMB, [ {'url': reverse('index'), 'title': '首页'},])
# 其他导航路径的添加
if pid:
# 有PID表示当前访问的权限是子权限 它有父权限 要让这个父权限展开
request.xxx = pid
# 获取 父 权限的 内容
p_dict = permissions_dict[str(pid)]
# 將父权限的内容 添加到 面包屑列表中
getattr(request,setting.BREADCRUMB).append(
{'url': p_dict['url'], 'title': p_dict['title']}
)
# 添加子 内容 到 列表中
getattr(request,setting.BREADCRUMB).append(
{'url': i['url'], 'title': i['title']}
)
else:
# 表示当前访问的权限是父权限 要让自己展开
request.xxx = id
getattr(request,setting.BREADCRUMB).append(
{'url': i['url'], 'title': i['title']}
)
信创建 inclusion_tag 获取 面包屑列表
@register.inclusion_tag('rbac/breadcrumb.html')
def breadcrumb(request):
breadcrumb_list = getattr(request,setting.BREADCRUMB)
return {'breadcrumb_list': breadcrumb_list}
HTML 页面 rbac/breadcrumb.html
<ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;">
{% for bread in breadcrumb_list %}
{% if forloop.last %}
<li>{{ bread.title }}</li>
{% else %}
<li><a href="{{ bread.url }}">{{ bread.title }}</a></li>
{% endif %}
{% endfor %}
</ol>
在 母版中使用
{% breadcrumb request %}
用到反射 (反射复习)
同过 name 别名 来判断 路径 將name 存放在 权限中
name = models.CharField(max_length=32, verbose_name='url别名')
存放所有 权限的 别名
获取 自己的url别名 以及
'permissions__paren__name', # 关联的 归属 权限 名字
'permissions__name', # url别名
用别名做 key 添加 关联字段的 名字
# 添加所有的 权限 url 使用 url 别名 当做 Key
permissions_dict[item['permissions__name']] = (
{'url': item['permissions__url'],
'id': item['permissions__id'],
'p_name': item['permissions__paren__name'], # 添加 查询 当前关联的 权限的名字
'pid': item['permissions__paren_id'],
'title': item['permissions__title']})
在中间件中 获取 p_name 的值
通过 值 找到 父及菜单的所有内容
id, pid, p_name = i['id'], i['pid'], i['p_name']
p_dict = permissions_dict[p_name] 查找 父及菜单内容
创建 filter 过滤器 反回 T or F 来判断 是否显示 标签
@register.filter()
def has_permission(request, name):
# 判断name是否在权限的字典中
if name in request.session.get(settings.PERMISSION_SESSION_KEY):
return True
在母版中 使用
{% if request|has_permission:'customer_edit' and request|has_permission:'customer_del' %}
{% if request|has_permission:'customer_del' %}
获取所有的 一级 菜单 一级 权限 信息 做展示
修改 权限 信息的 数据结构 区分 二三级 菜单 循环进行展示
# 显示 一级菜单 联动 二及菜单
def menu_list(request):
menu_obj = models.Menu.objects.all()
# 获取 菜单的 id
mid = request.GET.get('mid')
if mid:
# 如果有 条件 则对数据进行筛选
permission_all = models.Permission.objects.filter(Q(menu_id=mid) | Q(paren__menu_id=mid))
else:
permission_all = models.Permission.objects.all()
# 实例化 有序字典 修改 数据结构 將 数据分为 二三级菜单 存入 有序字典中
permission_dict = OrderedDict()
for item in permission_query_dict:
# 判断 二级菜单
if item.get('menu_id'):
permission_dict[item['id']] = item
item['children'] = []
for item in permission_query_dict:
# 判断三级菜单
pid = item.get('paren_id')
if pid:
permission_dict[pid]['children'].append(item)
print(permission_dict)
html
{% extends 'layout.html' %}
{% block css %}
<style>
.permission-area tr.root {
background-color: #dff0d8;
}
.menu-body tr.active {
background-color: #f1f7fd;
border-left: 3px solid #fdc00f;
}
</style>
{% endblock %}
{% block content %}
<div class="col-sm-3">
<div class="panel panel-info" style="margin: 20px;">
<div class="panel-heading"><i class="fa fa-book"></i> 菜单管理
<a href="{% url 'menu_add' %}" class="btn btn-sm btn-success pull-right"
style="margin-top: -2px; padding: 2px 7px">
<i class="fa fa-plus"></i> 新建</a>
</div>
<table class="table table-hover">
<thead>
<tr>
<th>名称</th>
<th>图标</th>
<th>操作</th>
</tr>
</thead>
<tbody class="menu-body">
{% for field in menu_obj %}
{# field.pk|safe 将数字转义为字符串 #}
<tr class="{% if field.pk|safe == mid %}active{% endif %}">
<td><a href="?mid={{ field.pk }}">{{ field.title }}</a></td>
<td><i class="fa {{ field.font }}"></i></td>
<td>
<a href="{% url 'menu_edit' field.pk %}" style=""><i class="fa fa-pencil-square-o"></i></a>
<a href="{% url 'menu_del' field.pk %}" style="color: red;"><i class="fa fa-trash"></i></a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
<div class="col-sm-9">
<div class="panel panel-info" style="margin: 20px;">
<div class="panel-heading"><i class="fa fa-th"></i> 权限管理
<a href="" class="btn btn-sm btn-warning pull-right" style="margin-top: -2px; padding: 2px 7px">
<i class="fa fa-mail-forward"></i> 批量操作</a>
<a href="{% url 'permission_add' %}" class="btn btn-sm btn-success pull-right" style="margin-top: -2px; padding: 2px 7px">
<i class="fa fa-plus-circle"></i> 新建</a>
</div>
<table class="table table-hover">
<thead>
<tr>
<th>描述</th>
<th>URR</th>
<th>URR别名</th>
<th>操作</th>
</tr>
</thead>
<tbody class="permission-area">
{% for p_permission in permission_dict %}
{# 二级菜单的 展示 #}
<tr class="root" id="{{ p_permission.id }}">
<td class="title">
<i class="fa fa-caret-down"></i>
{{ p_permission.title }}</td>
<td>{{ p_permission.url }}</td>
<td>{{ p_permission.name }}</td>
<td>
<a href="{% url 'permission_edit' p_permission.id %}" style=""><i class="fa fa-pencil-square-o"></i></a>
<a href="" style="color: red;"><i class="fa fa-trash"></i></a>
</td>
</tr>
{% for c_permission in p_permission.children %}
三级菜单的展示
<tr pid="{{ p_permission.id }}">
<td>{{ c_permission.title }}</td>
<td>{{ c_permission.url }}</td>
<td>{{ c_permission.name }}</td>
<td>
<a href="{% url 'permission_edit' c_permission.id %}" style=""><i class="fa fa-pencil-square-o"></i></a>
<a href="" style="color: red;"><i class="fa fa-trash"></i></a>
</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
{% block js %}
<script>
$('.permission-area').on('click', '.root .title', function () {
var caret = $(this).find('i');
var id = $(this).parent().attr('id');
if (caret.hasClass('fa-caret-right')) {
caret.removeClass('fa-caret-right').addClass('fa-caret-down');
$(this).parent().nextAll('tr[pid="' + id + '"]').removeClass('hide');
} else {
caret.removeClass('fa-caret-down').addClass('fa-caret-right');
$(this).parent().nextAll('tr[pid="' + id + '"]').addClass('hide');
}
})
</script>
{% endblock %}
有一个要应用的项目
把rbac的app拷贝到新项目中,注册
生成rbac相关的表
使用admin录入权限信息
应用登录后权限信息的初始化
from rbac.service.permission import init_permisson
from rbac.models import User
# 登录成功后
init_permisson(request,obj)
使用权限的中间件
MIDDLEWARE = [
...
'rbac.middlewares.rbac.RbacMiddleware'
]
? 在settings中进行配置
# ################################ 权限的配置 ################################
# 权限的key
PERMISSION_SESSION_KEY = 'permissions'
# 菜单的key
PERMISSION_MENU_KEY = 'menus'
WHITE_LIST = [
r'^/login/$',
r'^/reg/$',
r'^/admin/.*',
]
7.应用动态生成一级菜单
<link rel="stylesheet" href="{% static 'css/menu.css' %} "/>
{% load rbac %}
{% menu request %}
2.动态生成二级菜单
信息列表 - 一级菜单
? 客户列表 - 二级菜单
财务列表
? 缴费列表
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from django.utils.safestring import mark_safe
import requests
from bs4 import BeautifulSoup
response = requests.get(
url='http://fontawesome.dashgame.com/',
)
response.encoding = 'utf-8'
soup = BeautifulSoup(response.text, 'html.parser')
web = soup.find(attrs={'id': 'web-application'})
icon_list = []
for item in web.find_all(attrs={'class': 'fa-hover'}):
tag = item.find('i')
class_name = tag.get('class')[1]
icon_list.append([class_name, str(tag)])
print(icon_list)
class User(models.Model):
"""
用户表
"""
# name = models.CharField(max_length=32, verbose_name='名称')
# password = models.CharField(max_length=32, verbose_name='密码')
roles = models.ManyToManyField(Role, verbose_name='用户拥有的角色', blank=True)
# def __str__(self):
# return self.name
class Meta:
abstract = True # 数据库迁移时候不会生成表,用来做基类
class UserProfile(User, models.Model):
url(r'rbac/', include('rbac.urls',namespace='rbac'))
菜单管理
权限的录入
角色管理
分配权限
应用上权限
# 权限的key
PERMISSION_SESSION_KEY = 'permissions'
# 菜单的key
PERMISSION_MENU_KEY = 'menus'
WHITE_LIST = [
r'^/login/$',
r'^/reg/$',
r'^/admin/.*',
]
NO_PERMISSION_LIST = [
r'^/index/$',
r'^/logout/$',
]
# 路径导航
BREADCRUMB = 'breadcrumb_list'
# 路径导航
CURRENT_MENU = 'current_parent_id'
from rbac.service.permission import init_permisson
# 权限信息的初始化
init_permisson(request,obj)
动态生成二级菜单
```
导入CSS js
{% load rbac %}
{% menu request %}
```
应用路径导航
{% breadcrumb request %}
权限控制到按钮级别
{% load rbac %}
{% if request|has_permission:"consult_add" %}
<a href="{% url 'consult_add' %}" class="btn btn-primary btn-sm">添加</a>
{% endif %}
用户表加字段 存 session_key
通过session_key 拿到用户的session数据 更新权限
from django.contrib.sessions.models import Session
from django.contrib.sessions.backends.db import SessionStore
decode encode
加条件表
原文:https://www.cnblogs.com/zhang-zi-yi/p/10800426.html