(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
View Code

请求访问流程:

  中间件代码:

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("没有访问权限!")
View Code

数据初始化,构建数据结构,写入一个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": "",
                },
            ]

        },

    }

    '''
View Code

 

权限控制按钮显示隐藏

母版部分:

自定义模板过滤器:

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
View Code