这里用主机管理系统当做示例。

一、将rbac组件拷贝到项目中。

注意:

  1. rbac自己的静态文件、layout.html(被继承的模板)、bootstrap、fontsize、公共的css、jquery、layout里用到的图片也要拷贝进来
  2. 在settings.py注册rbac:
  3. 二级菜单和面包屑导航需要先注释掉
  4. 在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

注意:

  1. 改成abstract后就不能在admin里注册了
  2. 多对多关联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 %}

总结:目的是希望在任意系统中应用权限系统

  1. 用户登录 + 用户首页 + 用户注销 + 业务逻辑

  2. 业务逻辑开发。注意,开发时要灵活的去设计layout.html中的两个inclusion_tag

  1. 权限信息的录入

  2. 配置文件

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/',
]
  1. 粒度到按钮级别的控制

最新文章

  1. STC系列STC10F芯片解密STC10L单片机破解复制技术
  2. 真正高效的SQLSERVER分页查询(多种方案)
  3. install openvpn and openvpn manager in ubuntu
  4. 细说.NET中的多线程 (三 使用Task)
  5. MVC中几种常用ActionResult
  6. 纯PHP实现定时器任务(Timer)
  7. 金山词霸每日一句开放平台 .NET demo
  8. Codeforces 731D Funny Game
  9. 异步编程中使用帮助类来实现Thread.Start()的示例
  10. HTML&amp;CSS基础学习笔记1.30-颜色的表达
  11. ajax post传值
  12. properties 文件的中文转ASCII
  13. Servlet的学习之Cookie
  14. hdu 5106 Bits Problem(数位dp)
  15. HDU 2520 我是菜鸟,我怕谁
  16. 江湖问题研究-- intent传递有没有大小限制,是多少?
  17. 数据读取(SQL)与文本写入(fileStream)
  18. SSM框架整合(Spring+SpringMVC+MyBatis+Oracle)
  19. php Date()函数输出中文年月日时分秒
  20. 记时,耗时,Stopwatch

热门文章

  1. redis数据类型--个人常规用法
  2. 基于php缓存的详解
  3. docker exit status 255解决
  4. linux下的idea的界面问题,错位以及各种...
  5. KindEditor编辑器使用
  6. Java学习笔记--继承和多态(上)
  7. Java爬虫初体验
  8. 面向对象之套接字(socket)和黏包
  9. Jquery里面的$(this)和this, 有什么区别
  10. dsniff