ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

rbac组件之动态二级菜单之权限粒度控制到按钮

2022-02-01 19:33:07  阅读:192  来源: 互联网

标签:customer __ 菜单 title url rbac 粒度 id permissions


对于用户没有权限的按钮,也可以将操作按钮不渲染到前端页面,实现步骤如下:

第一步:修改Permission权限表字段

class Permission(models.Model):
    """权限表"""
    title = models.CharField(
        verbose_name="权限名称",
        max_length=32,
    )
    url = models.CharField(
        verbose_name="含正则URL",
        max_length=128,
    )
    menu = models.ForeignKey(
        to="Menu",
        on_delete=models.CASCADE,
        verbose_name="所属二级菜单",
        null=True,  # 并不是所有的url都可以做二级菜单,所以这里需要设置null=True
        blank=True,
        help_text="null表示不是二级菜单,非null表示是二级菜单",
    )
    pid = models.ForeignKey(
        verbose_name="关联的权限",
        to="Permission",
        null=True,  # 如果是二级菜单,那么此字段为空,非二级菜单此字段不为空
        blank=True,
        on_delete=models.CASCADE,
        help_text="对于非菜单权限需要选择一个可以成为菜单的权限,用于做默认展开和选中菜单",
        related_name="parents",
    )
    name = models.CharField(
        verbose_name="URL别名",
        max_length=32,
        unique=True,
    )

    def __str__(self):
        return self.title

第二步:权限初始化过程中,ORM取出的数据信息加上name字段,将权限信息数据结构换成字典,字典键是该url的name字段,值和之前一样

from django.conf import settings


def init_permission(current_user, request):
    permission_queryset = current_user.roles.filter(
        permissions__isnull=False,
    ).values(
        "permissions__id",  # 二级菜单id
        "permissions__url",  # 二级菜单url
        "permissions__title",  # 二级菜单名称
        "permissions__menu__id",  # 一级菜单ID
        "permissions__menu__title",  # 一级菜单名称
        "permissions__menu__icon",  # 一级菜单图标
        "permissions__pid_id",  # 非菜单url的自关联pid值,如果是二级菜单那么该字段值为空
        "permissions__pid__title",  # 路径导航
        "permissions__pid__url",  # 路径导航
        "permissions__name",
    ).distinct()
    permission_dict = {}  # 存放用户的权限数据信息,变成一个字典,key就是url的name
    menu_dict = {}  # 存放菜单信息
    for item in permission_queryset:
        permission_dict[item["permissions__name"]] = {
                "id": item["permissions__id"],  # 如果是二级菜单,那么需要用到此字段与菜单信息进行比较
                "url": item["permissions__url"],
                "title": item["permissions__title"],  # 路径导航
                "pid": item["permissions__pid_id"],  # 如果此字段为空,那么说明该url是二级菜单;如果不为空,那么需要用此字段与菜单信息进行比较
                "p_title": item["permissions__pid__title"],  # 路径导航
                "p_url": item["permissions__pid__url"],  # 路径导航
            }
        menu_id = item["permissions__menu__id"]  # 取到二级菜单所对应的一级菜单的id,如果不能做二级菜单的,那么这个字段值是null
        if not menu_id:
            continue
        node = {
            "id": item["permissions__id"],
            "title": item["permissions__title"],
            "url": item["permissions__url"],
        }  # 二级菜单数据信息,方便后续添加
        if menu_id in menu_dict:
            menu_dict[menu_id]["children"].append(node)  # 如果一级菜单已经存在,那么直接添加二级菜单数据信息即可
        else:
            # 如果一级菜单不存在,那么还需要添加一级菜单的数据信息和二级菜单的数据信息
            menu_dict[menu_id] = {
                "title": item["permissions__menu__title"],
                "icon": item["permissions__menu__icon"],
                "children": [node, ],
            }
    request.session[settings.PERMISSION_SESSION_KEY] = permission_dict
    request.session[settings.MENU_SESSION_KEY] = menu_dict


"""
权限信息
permission_dict = {
                    'customer_list': {'id': 1, 'url': '/customer/list/', 'title': '客户列表', 'pid': None, 'p_title': None, 'p_url': None},
                    'customer_add': {'id': 2, 'url': '/customer/add/', 'title': '添加客户', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'customer_del': {'id': 3, 'url': '/customer/del/(?P<cid>\\d+)/', 'title': '删除客户', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'customer_edit': {'id': 4, 'url': '/customer/edit/(?P<cid>\\d+)/', 'title': '修改客户', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'customer_import': {'id': 5, 'url': '/customer/import/', 'title': '批量导入', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'customer_tpl': {'id': 6, 'url': '/customer/tpl/', 'title': '下载模板', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'payment_list': {'id': 7, 'url': '/payment/list/', 'title': '账单列表', 'pid': None, 'p_title': None, 'p_url': None},
                    'payment_add': {'id': 8, 'url': '/payment/add/', 'title': '添加账单', 'pid': 7, 'p_title': '账单列表', 'p_url': '/payment/list/'},
                    'payment_del': {'id': 9, 'url': '/payment/del/(?P<pid>\\d+)/', 'title': '删除账单', 'pid': 7, 'p_title': '账单列表', 'p_url': '/payment/list/'},
                    'payment_edit': {'id': 10, 'url': '/payment/edit/(?P<pid>\\d+)/', 'title': '修改账单', 'pid': 7, 'p_title': '账单列表', 'p_url': '/payment/list/'}
                    }
菜单信息
menu_dict = {'1': {
                    'title': '信息管理', 
                    'icon': 'fa-camera-retro',
                    'children': [{'id': 1, 'title': '客户列表', 'url': '/customer/list/'}]},
            '2': {
                    'title': '用户管理', 
                    'icon': 'fa-fire',
                    'children': [{'id': 7, 'title': '账单列表', 'url': '/payment/list/'}]}}
"""

第三步:在中间件对权限进行判断时,用到了权限数据信息,权限数据信息结构发生了变化,所以取值时也要进行修改

from django.utils.deprecation import MiddlewareMixin
from django.conf import settings
import re
from django.shortcuts import HttpResponse


class RbacMiddleware(MiddlewareMixin):
    def process_request(self, request):
        current_url = request.path_info
        for url in settings.VALID_URL_LIST:
            if re.match(url, current_url):
                return None
        permission_dict = request.session.get(settings.PERMISSION_SESSION_KEY)
        if not permission_dict:
            return HttpResponse("未获取到用户权限信息,请重新登录...")
        flag = False
        url_record = [
            {"title": "首页", "url": "#"},
        ]  # 路径导航列表
        for url in permission_dict.values():  # 循环字典的values(),其它不变
            reg = "^%s$" % url["url"]
            if re.match(reg, current_url):
                flag = True
                request.current_selected_permission = url["pid"] or url["id"]  # pid不为空,那么值为pid;pid为空,那么值为id
                # 路径导航
                if not url["pid"]:
                    url_record.extend(
                        [{"title": url["title"], "url": url["url"], "class": "active"}]
                    )
                else:
                    url_record.extend(
                        [
                            {"title": url["p_title"], "url": url["p_url"]},
                            {"title": url["title"], "url": url["url"], "class": "active"},
                        ]
                    )
                request.url_record = url_record  # 路径导航
                break
        if not flag:
            return HttpResponse("你无权访问,请速速撤离...")


"""
permission_dict = {
                    'customer_list': {'id': 1, 'url': '/customer/list/', 'title': '客户列表', 'pid': None, 'p_title': None, 'p_url': None},
                    'customer_add': {'id': 2, 'url': '/customer/add/', 'title': '添加客户', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'customer_del': {'id': 3, 'url': '/customer/del/(?P<cid>\\d+)/', 'title': '删除客户', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'customer_edit': {'id': 4, 'url': '/customer/edit/(?P<cid>\\d+)/', 'title': '修改客户', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'customer_import': {'id': 5, 'url': '/customer/import/', 'title': '批量导入', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'customer_tpl': {'id': 6, 'url': '/customer/tpl/', 'title': '下载模板', 'pid': 1, 'p_title': '客户列表', 'p_url': '/customer/list/'},
                    'payment_list': {'id': 7, 'url': '/payment/list/', 'title': '账单列表', 'pid': None, 'p_title': None, 'p_url': None},
                    'payment_add': {'id': 8, 'url': '/payment/add/', 'title': '添加账单', 'pid': 7, 'p_title': '账单列表', 'p_url': '/payment/list/'},
                    'payment_del': {'id': 9, 'url': '/payment/del/(?P<pid>\\d+)/', 'title': '删除账单', 'pid': 7, 'p_title': '账单列表', 'p_url': '/payment/list/'},
                    'payment_edit': {'id': 10, 'url': '/payment/edit/(?P<pid>\\d+)/', 'title': '修改账单', 'pid': 7, 'p_title': '账单列表', 'p_url': '/payment/list/'}
                    }
"""

第四步:自定义filter标签,这样前端页面直接调用该filter即可

from django.template import Library
from django.conf import settings
import re
from collections import OrderedDict


register = Library()


@register.filter
def has_permissions(request, name):
    """
    最多有两个参数
    :param request:
    :param name:
    :return:
    """
    if name in request.session.get(settings.PERMISSION_SESSION_KEY):
        return True

第五步:前端调用

app01/templates/customer_list.html

{% extends 'layout.html' %}
{# 要先引用rbac #}
{% load rbac %}

{% block content %}

    <div class="luffy-container">
        <div class="btn-group" style="margin: 5px 0">
            {# 调用方式,request是第一个参数,"customer_add"是第二个参数,"customer_add"也可以是写路由分发时的别名,这样可以方便解耦 #}
            {% if request|has_permissions:"customer_add" %}
                <a class="btn btn-default" href="/customer/add/">
                    <i class="fa fa-plus-square" aria-hidden="true"></i> 添加客户
                </a>
            {% endif %}
            {% if request|has_permissions:"customer_import" %}
                <a class="btn btn-default" href="/customer/import/">
                    <i class="fa fa-file-excel-o" aria-hidden="true"></i> 批量导入
                </a>
            {% endif %}
        </div>
        <table class="table table-bordered table-hover">
            <thead>
            <tr>
                <th>ID</th>
                <th>客户姓名</th>
                <th>年龄</th>
                <th>邮箱</th>
                <th>公司</th>
                {% if request|has_permissions:"customer_edit" or request|has_permissions:"customer_del" %}
                    <th>选项</th>
                {% endif %}
            </tr>
            </thead>
            <tbody>
            {% for row in data_list %}
                <tr>
                    <td>{{ row.id }}</td>
                    <td>{{ row.name }}</td>
                    <td>{{ row.age }}</td>
                    <td>{{ row.email }}</td>
                    <td>{{ row.company }}</td>
                    <td>
                        {% if request|has_permissions:"customer_edit" %}
                            <a style="color: #333333;" href="/customer/edit/{{ row.id }}/">
                            <i class="fa fa-edit" aria-hidden="true"></i></a>
                        {% endif %}
                        {% if request|has_permissions:"customer_del" %}
                            <a style="color: #d9534f;" href="/customer/del/{{ row.id }}/"><i class="fa fa-trash-o"></i></a>
                        {% endif %}
                    </td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </div>
{% endblock %}

app01/templates/payment_list.html

{% extends 'layout.html' %}
{% load rbac %}

{% block content %}

    <div class="luffy-container">
        <div style="margin: 5px 0;">
            {% if request|has_permissions:"payment_add" %}
                <a class="btn btn-success" href="/payment/add/">
                    <i class="fa fa-plus-square" aria-hidden="true"></i> 添加缴费记录
                </a>
            {% endif %}
        </div>
        <table class="table table-bordered table-hover">
            <thead>
            <tr>
                <th>ID</th>
                <th>客户姓名</th>
                <th>金额</th>
                <th>付费时间</th>
                {% if request|has_permissions:"payment_edit" or request|has_permissions:"payment_del" %}
                    <th>选项</th>
                {% endif %}
            </tr>
            </thead>
            <tbody>
            {% for row in data_list %}
                <tr>
                    <td>{{ row.id }}</td>
                    <td>{{ row.customer.name }}</td>
                    <td>{{ row.money }}</td>
                    <td>{{ row.create_time|date:"Y-m-d H:i:s" }}</td>
                    <td>
                        {% if request|has_permissions:"payment_edit" %}
                            <a style="color: #333333;" href="/payment/edit/{{ row.id }}/">
                                <i class="fa fa-edit" aria-hidden="true"></i></a>
                        {% endif %}
                        {% if request|has_permissions:"payment_del" %}
                            <a style="color: #d9534f;" href="/payment/del/{{ row.id }}/">
                                <i class="fa fa-trash-o"></i></a>
                        {% endif %}
                    </td>
                </tr>
            {% endfor %}
            </tbody>
        </table>
    </div>
{% endblock %}

示例图:

 

 

链接:https://pan.baidu.com/s/1fGUozEPoYFLb9S4fY94MoQ
提取码:abab

标签:customer,__,菜单,title,url,rbac,粒度,id,permissions
来源: https://www.cnblogs.com/xuewei95/p/15859473.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有