权限组件(15):rbac的使用文档和在业务中的应用
这里用主机管理系统当做示例。
一、将rbac组件拷贝到项目中。
注意:
- rbac自己的静态文件、layout.html(被继承的模板)、bootstrap、fontsize、公共的css、jquery、layout里用到的图片也要拷贝进来
- 在settings.py注册rbac:
- 二级菜单和面包屑导航需要先注释掉
- 在settings中将LANGUAGE_CODE = 'en-us'改为LANGUAGE_CODE = 'zh-hans'
在layout.html里注释掉二级菜单和面包屑导航
<div class="pg-body">
<div class="left-menu">
<div class="menu-body">
{# {% multi_menu request %}#}
</div>
</div>
<div class="right-body">
{# {% breadcrumb request %}#}
{% block content %} {% endblock %}
</div>
</div>
在settings.py里注册rbac
INSTALLED_APPS = [
...
'rbac.apps.RbacConfig'
...
]
二、将rbac/migrations目录中的数据库迁移记录删除(init.py不能删除)
三、业务系统中用户表结构的设计
业务表结构中的用户表需要和rbac中的用户表有继承关系如:
- rbac/models.py
class UserInfo(models.Model):
"""
用户表
"""
name = models.CharField(verbose_name='用户名', max_length=32)
password = models.CharField(verbose_name='密码', max_length=64)
email = models.CharField(verbose_name='邮箱', max_length=32)
roles = models.ManyToManyField(verbose_name='拥有的所有角色', to=Role, blank=True)
# 去掉引号就把Role这个类的内存地址也继承过去了,这样做数据库迁移就不会报错了 def __str__(self):
return self.name class Meta:
# django以后再做数据库迁移时,不再为UserInfo类创建相关的表以及表结构了
# 此类可以当做"父类",被其他Model类继承。里面的字段就自动过度给继承它的类了
abstract = True
注意:
- 改成abstract后就不能在admin里注册了
- 多对多关联Role的时候不能加引号
- 业务/models.py
from rbac.models import UserInfo as RbacUserInfo class Host(models.Model): """主机表"""
hostname = models.CharField(verbose_name='主机名', max_length=32)
ip = models.GenericIPAddressField(verbose_name='IP', protocol='both')
department = models.ForeignKey(verbose_name='归属部门', to='Department', on_delete=models.CASCADE) def __str__(self):
return self.hostname class UserInfo(RbacUserInfo):
"""用户表""" phone = models.CharField(verbose_name='联系方式', max_length=32)
T1 = 1
T2 = 2
T3 = 3
level_choices = (
(T1, 'T1'),
(T2, 'T2'),
(T3, 'T3')
)
level = models.IntegerField(verbose_name='级别', choices=level_choices)
department = models.ForeignKey(verbose_name='部门', to='Department', on_delete=models.CASCADE)
迁移数据库
./manage.py makemigrations
./manage.py migrate
四、将业务系统中的用户表的路径写到配置文件
settings.py
# 业务中的用户表
RBAC_USER_MODEL_CLASS = 'host.models.UserInfo' # 用于在rbac分配权限时,读取业务表中的用户信息。
host换成你的业务app
在权限组件的视图函数中将用户表改为新的,所有的UserInfo都要改成user_model_class
rbac/views/menu.py
...
from django.conf import settings
from django.utils.module_loading import import_string
... ...
def distribute_permissions(request):
"""
权限分配
:param request:
:return:
""" user_id = request.GET.get('uid') # user_object = models.UserInfo.objects.filter(id=user_id).first() # 之前的用户表,不要了 # 业务中的用户表
user_model_class = import_string(settings.RBAC_USER_MODEL_CLASS) # 自动根据字符串的形式,把这个类导入进来 user_object = user_model_class.objects.filter(id=user_id).first()
...
五、业务逻辑开发
1. 开发一个登陆功能
2.将所有的路由都设置一个name,用来反向生成url以及粒度控制到按钮级别的权限控制。如:
from django.contrib import admin
from django.urls import path, re_path from host.views import account
from host.views import user
from host.views import host urlpatterns = [
re_path(r'^admin/', admin.site.urls), re_path(r'^login/$', account.login, name='login'),
re_path(r'^logout/$', account.logout, name='logout'),
re_path(r'^index/$', account.index, name='index'), re_path(r'^user/list/$', user.user_list, name='user_list'),
re_path(r'^user/add/$', user.user_add, name='user_add'),
re_path(r'^user/edit/(?P<pk>\d+)/$', user.user_edit, name='user_edit'),
re_path(r'^user/delete/(?P<pk>\d+)/$', user.user_delete, name='user_delete'),
re_path(r'^user/reset/pwd/(?P<pk>\d+)/$', user.user_reset_pwd, name='user_reset_pwd'), re_path(r'^host/list/$', host.host_list, name='host_list'),
re_path(r'^host/add/$', host.host_add, name='host_add'),
re_path(r'^host/edit/(?P<pk>\d+)/$', host.host_edit, name='host_edit'),
re_path(r'^host/delete/(?P<pk>\d+)/$', host.host_delete, name='host_delete'), ]
六、权限信息的录入
在url中添加rbac的路由分发。注意:必须设置namesapce
项目/urls.py
...
from django.urls import path, re_path, include
... urlpatterns = [
...
path('rbac/', include(('rbac.urls', 'rbac'))),
...
]
注意:rbac中的用户管理相关的URL配置要注释掉或删除掉
添加菜单、分配角色、录入权限
rbac提供的地址进行操作
菜单列表 - http://127.0.0.1:8000/rbac/menu/list/
角色列表 - http://127.0.0.1:8000/rbac/role/list/
权限分配 - http://127.0.0.1:8000/rbac/distribute/permissions/
1. 先添加一级菜单,然后批量录入二级菜单和权限
2. 添加完菜单后创建角色
3. 最后记得分配权限,否则后面加上中间件后会提示无权限访问
相关配置:自动发现URL时,排除的URL
AUTO_DISCOVER_EXCLUDE = [
'/admin/',
'/login/',
'/logout/',
'/index/',
]
注意:如果排除的URL中,如admin、login等用的是django2.0新出的path方法,那么正则匹配的之后需要写成/admin.*,因为path会在admin后面加一个斜杠(\)。/admin/配置的话就会在自动发现URL中出现一推这样的URL:/admin/
七、编写用户登录的逻辑【进行权限的初始化】
def login(request):
"""
登录
:param request:
:return:
"""
if request.method == 'GET':
return render(request, 'login.html')
user = request.POST.get('username')
pwd = request.POST.get('password') user_obj = models.UserInfo.objects.filter(name=user, password=pwd).first() if not user_obj:
return render(request, 'login.html', {'error': '用户名或密码错误'}) # 用户权限信息的初始化
init_permission(user_obj, request) return redirect(reverse('index'))
相关配置:权限和菜单的session key:
PERMISSION_SESSION_KEY = 'permission_url_list_key'
MENU_SESSION_KEY = 'permission_menu_key'
八、编写一个首页的逻辑
def index(request):
return render(request, 'index.html')
相关配置:
# 需要登录,但无需权限的URL
NO_PERMISSION_LIST = [
'/logout/',
'/index/',
]
在中间件新增无需权限校验,但是需要登录才能访问的功能
...
url_record = [
{'title': '首页', 'url': '#'}
] # 此处代码进行判断:/logout/,/index/ 无需权限校验,但是需要登录才能访问
for url in settings.NO_PERMISSION_LIST:
if re.match(url, request.path_info):
# 需要登录,但无需权限校验
request.current_selected_permission = 0 # 等于0就是没有默认选中,和菜单没有关联上,就不会做默认展开
request.breadcrumb = url_record
return None has_permission = False
...
九、通过中间件进行权限的校验
rbac/middlewares/rabc.py
# 权限校验
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware', 'rbac.middlewares.rbac.RbacMiddleware',
]
白名单
# 白名单,无需登录就可以访问
WHITE_LIST = ['/login/', '/admin/.*']
十、粒度到按钮级别的控制
host/templates/user_list.html
{% extends 'layout.html' %}
{% load rbac %} {% block content %} <h1>用户列表</h1>
<div class="custom-container">
<div class="btn-group" style="margin: 5px 0">
{% if request|has_permission:'user_add' %} <!-- 控制增加按钮 -->
<a class="btn btn-default" href="{% memory_url request 'user_add' %}">
<i class="fa fa-plus-square" aria-hidden="true"></i> 添加用户
</a>
{% endif %}
</div> <table class="table table-bordered table-hover">
<thead>
<tr>
<th>用户名</th>
<th>邮箱</th>
<th>级别</th>
<th>部门</th>
<th>手机</th>
{% if request|has_permission:'user_reset_pwd' %} <!-- 控制重置密码按钮 -->
<th>重置密码</th>
{% endif %}
{% if request|has_permission:'user_edit' or 'user_delete' %}
<th>操作</th>
{% endif %}
</tr>
</thead>
<tbody>
{% for row in user_queryset %}
<tr>
<td>{{ row.name }}</td>
<td>{{ row.email }}</td>
<td>{{ row.get_level_display }}</td>
<td>{{ row.department.title }}</td>
<td>{{ row.phone }}</td> {% if request|has_permission:'user_reset_pwd' %}
<td>
<a href="{% memory_url request 'user_reset_pwd' pk=row.id %}">重置密码</a>
</td>
{% endif %} {% if request|has_permission:'user_edit' or 'user_delete' %} <!-- 控制编辑和删除按钮 -->
<td>
{% if request|has_permission:'user_edit' %}
<a style="color: #333333; font-size:18px"
href="{% memory_url request 'user_edit' pk=row.id %}">
<i class="fa fa-edit" aria-hidden="true"></i></a>
{% endif %} {% if request|has_permission:'user_delete' %}
<a style="color: red; font-size:18px"
href="{% memory_url request 'user_delete' pk=row.id %}">
<i class="fa fa-trash-o" aria-hidden="true"></i></a>
{% endif %} </td>
{% endif %} </tr>
{% endfor %}
</tbody>
</table> </div> {% endblock content %}
总结:目的是希望在任意系统中应用权限系统
用户登录 + 用户首页 + 用户注销 + 业务逻辑
业务逻辑开发。注意,开发时要灵活的去设计layout.html中的两个inclusion_tag
权限信息的录入
配置文件
INSTALLED_APPS = [
...
'host.apps.HostConfig',
'rbac.apps.RbacConfig'
...
] MIDDLEWARE = [
...
'rbac.middlewares.rbac.RbacMiddleware',
...
] # 业务中的用户表
RBAC_USER_MODEL_CLASS = 'host.models.UserInfo' # 权限在session中存储的key
PERMISSION_SESSION_KEY = 'permission_url_list_key' # 菜单在Session中存储的key
MENU_SESSION_KEY = 'permission_menu_key' # 白名单
WHITE_LIST = ['/login/', '/admin/.*'] # 自动发现路由中URL时,排除的URL
AUTO_DISCOVER_EXCLUDE = [
'/admin.*',
'/login.*',
'/logout.*',
'/index.*',
] # 需要登录,但无需权限的URL
NO_PERMISSION_LIST = [
'/logout/',
'/index/',
]
- 粒度到按钮级别的控制
权限组件(15):rbac的使用文档和在业务中的应用的更多相关文章
- ElasticSearch 学习记录之 分布式文档存储往ES中存数据和取数据的原理
分布式文档存储 ES分布式特性 屏蔽了分布式系统的复杂性 集群内的原理 垂直扩容和水平扩容 真正的扩容能力是来自于水平扩容–为集群添加更多的节点,并且将负载压力和稳定性分散到这些节点中 ES集群特点 ...
- Xml学习笔记(3)利用递归解析Xml文档添加到TreeView中
利用递归解析Xml文档添加到TreeView中 private void Form1_Load(object sender, EventArgs e) { XmlDocument doc = new ...
- 使用Spire.Doc组件利用模板导出Word文档
以前一直是用Office的组件实现Word文档导出,但是让客户在服务器安装Office,涉及到版权:而且Office安装,包括权限配置也是比较麻烦. 现在流行使用第三方组件来实现对Office的操作, ...
- 使用 swagger组件给asp.net webapi文档生成
1.名词解释 Swagger 是一个规范和完整的框架,用于生成.描述.调用和可视化 RESTful 风格的 Web 服务.总体目标是使客户端和文件系统作为服务器以同样的速度来更新.文件的方法,参数和模 ...
- ABBYY FineReader 15新增智能PDF文档转换功能
ABBYY FineReader 15(Windows系统)新增智能PDF文档转换功能,可自动检测导入PDF数字文档的文本层质量,确保转变为可编辑格式后的准确结果:从表单字段和文本框中提取文本,准确保 ...
- ABBYY FineReader 15扫描和保存文档详解
通过使用ABBYY FineReader 15 OCR文字识别软件的扫描和保存文档功能,用户可使用扫描仪或数码照相机获得图像文档,然后再转换为各种数字格式文档. 在"新任务窗口"中 ...
- ABBYY FineReader 15 如何为PDF文档添加页眉页脚
页眉.页脚是文档页面顶部或底部重复出现的文本信息.很多用户会习惯在文档页面的顶部与底部区域添加页眉.页脚来展现页码.文档标题.作者姓名.品牌名称等附加信息.而ABBYY FineReader 15(W ...
- Java高级特性 第15节 解析XML文档(3) - JDOM和DOM4J技术
一.JDOM解析 特征: 1.仅使用具体类,而不使用接口. 2.API大量使用了Collections类. Jdom由6个包构成: Element类表示XML文档的元素 org.jdom: 解析xml ...
- 使用Word API打开Word文档 ASP.NET编程中常用到的27个函数集
使用Word API(非Openxml)打开Word文档简单示例(必须安装Word) 首先需要引入参照Microsoft.Office.Interop.Word 代码示例如下: public void ...
随机推荐
- Quartz.NET持久化
Quartz.NET所用到的数据库表结构 官方提供的各种数据库脚本:https://github.com/quartznet/quartznet/tree/master/database/tables ...
- JDK工具
在之前的教程中,我曾介绍过 这些工具.现在,我向大家介绍其中最重要的5个工具. 1.javap javap是一个Java类文件反汇编程序,可以查看Java编译器生成的字节码,是分析代码的一个好工具.让 ...
- 使用Fsharp 探索 Dotnet 平台
Fsharp的交互开发环境使得我们在了解DotNet平台时能够快速的获得需要的反馈. 反馈在任何技艺的磨练过程中必不可少,我认为也是最重要的环节之一.在“一万小时天才理论”中,著名的髓鞘质就是在快速有 ...
- JavaSE_2_关键字
1.介绍一下Syncronized锁,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么? synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下四种: ...
- 分享几道经典的javascript面试题
这几道题目还是有一点意思的,大家可以研究一番,对自己的技能提升绝对有帮助. 1.调用过程中输出的内容是什么 function fun(n, o) { console.log(o); return { ...
- Android RecycleView实现混合Item布局
首先来看看效果吧: 效果预览.png 本实例来自于慕课网的视屏http://www.imooc.com/video/13046,实现步骤可以自己去观看视屏,这里只记录了下实现的代码. 添加依赖: (1 ...
- 怎么旋转PDF文件的方向并保存成功
http://jingyan.baidu.com/article/59a015e39d7802f79488651e.html PDF格式的文档是非常普遍的一种阅读电子书格式,基本上非常好用了,不过有时 ...
- 【洛谷1337】[JSOI2004] 吊打XXX(模拟退火经典题)
点此看题面 大致题意: 一个平面上有\(n\)个点,每个点有1个权值,现在要选择平面上的一个点,使这\(n\)个点的权值乘上到达选定点的距离之和最小. 模拟退火 我们可以用模拟退火来做这道题. 先将\ ...
- 利用kvo实现列表倒计时
自己稍微记录一下,方便以后用到: 先创建一个定时器的类: #import "TimeCenter.h" @interface TimeCenter () @property (no ...
- Python——函数入门(三)
一.变量作用域 当程序定义一个变量时,这个变量是有它的作用范围的,变量的作用范围称为变量的作用域.根据变量的位置,分为两种: 局部变量:局部变量就是在函数中定义的变量,包括参数,都是局部变量,局部离开 ...