(1) 先将rbac组建移植到新的项目中
(2) 将settings中install_app中加入"rbac"
(3) 将新项目的用户表与rbac下的User表一对一关联
(4) 数据迁移
(5) 在登录成功后引入rbac下的initial_session方法,做登录用户的权限信息存储(注意user对象)
(6) 在setting是中引入rbac下的权限校验中间件
(7) 在项目的base模板中引入菜单样式,渲染显示
RBAC分析:
- 基于角色的权限管理;
- 权限等于用户可以访问的URL;
- 通过限制URL来限制权限;
RBAC表结构组成:

from django.db import models class Menu(models.Model): '''菜单表''' title = models.CharField(max_length=32, verbose_name='菜单') icon = models.CharField(max_length=32, verbose_name='图标', null=True, blank=True) def __str__(self): return self.title class Permission(models.Model): '''权限表''' title = models.CharField(max_length=32, verbose_name='标题') url = models.CharField(max_length=32, verbose_name='权限') menu = models.ForeignKey("Menu", on_delete=models.CASCADE, null=True,blank=True) name = models.CharField(max_length=32, verbose_name='url别名', default="") pid = models.ForeignKey("self", on_delete=models.CASCADE, 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(to='Permission', verbose_name='角色所拥有的权限', blank=True) def __str__(self): return self.name class User(models.Model): '''用户表''' # 要与userinfo里面对齐,在userinfo表中添加一个一对一的关系 name = models.CharField(max_length=32, verbose_name='用户名') password = models.CharField(max_length=32, verbose_name='密码') roles = models.ManyToManyField(to='Role', verbose_name='用户所拥有的角色', blank=True) def __str__(self): return self.name
请求访问流程:
中间件代码:

import re from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse, redirect from rbac.models import Permission class PermissionMiddleware(MiddlewareMixin): def process_request(self, request): current_path = request.path # 获取当前路径 # 设置白名单 for reg in ["/login/", "/get_valid_img/", "/admin/.*","/reg/","/rbac/permissions_tree/","/index/","/logout/ "]: ret = re.search(reg, current_path) if ret: return None # 校验是否登陆 user_id = request.session.get('user_id') if not user_id: return redirect("/login/") # 校验权限 permission_list = request.session.get("permission_list") ''' permission_list=[ {"url":"","id":"","pid":""}, {"url":"","id":"","pid":""}, {"url":"","id":"","pid":""}, ] ''' # 面包屑: # 路径导航列表 request.breadcrumb=[ { "title":"首页", "url":"/" }, ] # 校验当前路径有没有在权限列表中 for item in permission_list: reg = "^%s$"%item['url'] ret = re.search(reg,current_path) if ret: show_id = item["pid"] or item["id"] request.show_id = show_id # 确定面包屑列表 # 如果pid有值,说明是菜单权限,所以要把菜单和当前访问权限全都加入面包屑 if item["pid"]: # 查找当前pid权限对象 ppermission = Permission.objects.filter(pk=item["pid"]).first() request.breadcrumb.extend( [{ "title":ppermission.title, "url":ppermission.url },{ "title":item["title"], "url":request.path }] ) else: # 如果不是菜单权限,直接添加到面包屑 request.breadcrumb.append( { "title":item["title"], "url":item["url"] } ) return None return HttpResponse("没有访问权限!")
数据初始化,构建数据结构,写入一个py文件,在登录视图中登录成功后调用函数,获取到数据,注入session

from rbac.models import Role def initial_session(request,user): ''' 将当前登录人的所有权限录入session中 :param user: 当前登录人 ''' # 查询当前登录人的所有权限url,权限名,权限别名,权限id,父权限id,归属的菜单名,图标,id permissions = Role.objects.filter(user=user).values("permissions__url", "permissions__title", "permissions__name", "permissions__id", "permissions__pid", "permissions__menu__title", "permissions__menu__icon", "permissions__menu__id").distinct() permission_list = [] # 权限列表 permission_names = [] # 别名列表 permission_menu_dict = {} # 菜单 for item in permissions: # 构建权限列表 permission_list.append({ "url": item["permissions__url"], "id": item["permissions__id"], "pid": item["permissions__pid"], "title": item["permissions__title"], }) # 构建别名列表 permission_names.append(item["permissions__name"]) # 菜单权限 menu_pk = item["permissions__menu__id"] if menu_pk: if menu_pk not in permission_menu_dict: permission_menu_dict[menu_pk] = { "menu_title": item["permissions__menu__title"], "menu_icon": item["permissions__menu__icon"], "children": [ { "title": item["permissions__title"], "url": item["permissions__url"], "id": item["permissions__id"], } ], } else: permission_menu_dict[menu_pk]["children"].append({ "title": item["permissions__title"], "url": item["permissions__url"], "id": item["permissions__id"], }) # 将前面构建的数据注入session中 request.session["permission_list"] = permission_list request.session["permission_names"] = permission_names request.session["permission_menu_dict"] = permission_menu_dict ''' 元数据: [{ 'permissions__url': '/customer/list/', 'permissions__title': '客户列表', 'permissions__menu__title': '信息管理', 'permissions__menu__icon': 'fa fa-connectdevelop', 'permissions__menu__pk': 1 }, { 'permissions__url': '/mycustomer/', 'permissions__title': '我的私户', 'permissions__menu__title': '信息管理', 'permissions__menu__icon': 'fa fa-connectdevelop', 'permissions__menu__pk': 1 }, { 'permissions__url': '/payment/list/', 'permissions__title': '缴费列表', 'permissions__menu__title': '财务管理', 'permissions__menu__icon': 'fa fa-code-fork', 'permissions__menu__pk': 2 }, ] 目标数据: { 1: { "title": "信息管理", "icon": "", "children": [ { "title": "客户列表", "url": "", } ] }, 2: { "title": "财务管理", "icon": "", "children": [ { "title": "缴费列表", "url": "", }, ] }, } permission_menu_dict = { 1: { "title": "信息管理", "icon": "", "children": [ { "title": "客户列表", "url": "", }, { "title": "我的私户", "url": "", }, ] }, 2: { "title": "财务管理", "icon": "", "children": [ { "title": "缴费列表", "url": "", }, ] }, } '''
权限控制按钮显示隐藏
母版部分:
自定义模板过滤器:

import re from django.template import Library register = Library() # 自定义过滤器,控制点中的菜单边框显示隐藏 @register.inclusion_tag("menu.html") def get_menu_styles(request): permission_menu_dict = request.session.get("permission_menu_dict") for val in permission_menu_dict.values(): for item in val["children"]: val["class"] = "hide" if request.show_id == item["id"]: val["class"] = 'active' return {"permission_menu_dict":permission_menu_dict} @register.filter() def has_permission(btn_url,request): permission_names = request.session.get('permission_names') return btn_url in permission_names