Django+vue3权限菜单rabc设计和动态路由

news2024/11/17 3:37:25

本次是基于Django和vue实现

github源码:nineaiyu/xadmin-server: xadmin-基于Django+vue3的rbac权限管理系统 (github.com)

服务器设计及部分代码 

权限控制的话,可以基于Django的permission进行控制,并通过访问api的URL操作

核心代码如下

import re

from django.conf import settings
from rest_framework.exceptions import PermissionDenied, NotAuthenticated
from rest_framework.permissions import BasePermission

from system.models import Menu


def get_user_permission(user_obj):
    menu = []
    if user_obj.roles:
        menu_obj = Menu.objects.filter(userrole__in=user_obj.roles.all()).distinct()
        menu = menu_obj.filter(is_active=True, menu_type=2).values('path', 'component').all().distinct()
    return menu


class IsAuthenticated(BasePermission):
    """
    Allows access only to authenticated users.
    """

    def has_permission(self, request, view):
        auth = bool(request.user and request.user.is_authenticated)
        if auth:
            if request.user.is_superuser:
                return True
            url = request.path_info
            for w_url in settings.PERMISSION_WHITE_URL:
                if re.match(w_url, url):
                    return True
            permission_data = get_user_permission(request.user)
            for p_data in permission_data:
                if p_data.get('component') == request.method and re.match(f"/{p_data.get('path')}", url):
                    return True
            raise PermissionDenied('权限不足')
        else:
            raise NotAuthenticated('未授权认证')

因此,需要对menu表进行设计,由于涉及到了前端vue路由,因此,menu模型字段比较多,如下

class DbBaseModel(models.Model):
    created_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")
    updated_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    description = models.CharField(max_length=128, verbose_name="描述信息", null=True, blank=True)

    class Meta:
        abstract = True


class MenuMeta(DbBaseModel):
    title = models.CharField(verbose_name="菜单名称", max_length=256, null=True, blank=True)
    icon = models.CharField(verbose_name="菜单图标", max_length=256, null=True, blank=True)
    r_svg_name = models.CharField(verbose_name="菜单右侧额外图标iconfont名称,目前只支持iconfont", max_length=256,
                                  null=True, blank=True)
    is_show_menu = models.BooleanField(verbose_name="是否显示该菜单", default=True)
    is_show_parent = models.BooleanField(verbose_name="是否显示父级菜单", default=False)
    is_keepalive = models.BooleanField(verbose_name="是否开启页面缓存", default=False,
                                       help_text='开启后,会保存该页面的整体状态,刷新后会清空状态')
    frame_url = models.CharField(verbose_name="内嵌的iframe链接地址", max_length=256, null=True, blank=True)
    frame_loading = models.BooleanField(verbose_name="内嵌的iframe页面是否开启首次加载动画", default=False)

    transition_enter = models.CharField(verbose_name="当前页面进场动画", max_length=256, null=True, blank=True)
    transition_leave = models.CharField(verbose_name="当前页面离场动画", max_length=256, null=True, blank=True)

    is_hidden_tag = models.BooleanField(verbose_name="当前菜单名称或自定义信息禁止添加到标签页", default=False)
    dynamic_level = models.IntegerField(verbose_name="显示标签页最大数量", default=1)

    class Meta:
        verbose_name = "菜单元数据"
        verbose_name_plural = "菜单元数据"
        ordering = ("-created_time",)

    def __str__(self):
        return f"{self.title}-{self.description}"


class Menu(DbBaseModel):
    parent = models.ForeignKey(to='Menu', on_delete=models.SET_NULL, verbose_name="父节点", null=True, blank=True)

    menu_type_choices = ((0, '目录'), (1, '菜单'), (2, '权限'))
    menu_type = models.SmallIntegerField(choices=menu_type_choices, default=0, verbose_name="节点类型")

    name = models.CharField(verbose_name="组件英文名称", max_length=128, unique=True)
    rank = models.IntegerField(verbose_name="菜单顺序", default=9999)
    path = models.CharField(verbose_name="路由地址", max_length=256)
    component = models.CharField(verbose_name="组件地址", max_length=256, null=True, blank=True)
    is_active = models.BooleanField(verbose_name="是否启用该菜单", default=True)
    meta = models.OneToOneField(to=MenuMeta, on_delete=models.CASCADE, verbose_name="菜单元数据")
    method_choices = (('GET', 'get'), ('POST', 'post'), ('PUT', 'put'), ('DELETE', 'delete'))

    def delete(self, using=None, keep_parents=False):
        if self.meta:
            self.meta.delete(using, keep_parents)
        super().delete(using, keep_parents)

    class Meta:
        verbose_name = "菜单信息"
        verbose_name_plural = "菜单信息"
        ordering = ("-created_time",)

    def __str__(self):
        return f"{self.name}-{self.menu_type}-{self.meta.title}"

最重要的menu表已经设计完成,那么接下来就更简单了,还需要一个获取所有路由的方法,当添加权限的时候,可以方便的选择相应的路由权限

import re
from collections import OrderedDict

from django.conf import settings
from django.urls import URLPattern, URLResolver
from django.utils.module_loading import import_string


def check_show_url(url):
    for prefix in settings.PERMISSION_SHOW_PREFIX:
        if re.match(prefix, url):
            return True


def recursion_urls(pre_namespace, pre_url, urlpatterns, url_ordered_dict):
    """递归去获取URL
    :param pre_namespace: namespace前缀,以后用户拼接name
    :param pre_url: url前缀,以后用于拼接url
    :param urlpatterns: 路由关系列表
    :param url_ordered_dict: 用于保存递归中获取的所有路由
    """
    for item in urlpatterns:
        if isinstance(item, URLPattern):
            if not item.name:
                continue

            if pre_namespace:
                name = "%s:%s" % (pre_namespace, item.name)
            else:
                name = item.name
            if not item.name:
                raise Exception('URL路由中必须设置name属性')
            url = pre_url + item.pattern.regex.pattern.lstrip('^')
            # url = url.replace('^', '').replace('$', '')

            if check_show_url(url):
                url_ordered_dict[name] = {'name': name, 'url': url}

        elif isinstance(item, URLResolver):  # 路由分发,递归操作
            if pre_namespace:
                if item.namespace:
                    namespace = "%s:%s" % (pre_namespace, item.namespace)
                else:
                    namespace = item.namespace
            else:
                if item.namespace:
                    namespace = item.namespace
                else:
                    namespace = None
            recursion_urls(namespace, pre_url + item.pattern.regex.pattern.lstrip('^'), item.url_patterns,
                           url_ordered_dict)


def get_all_url_dict(pre_url='/'):
    """
       获取项目中所有的URL(必须有name别名)
    """
    url_ordered_dict = OrderedDict()
    md = import_string(settings.ROOT_URLCONF)
    url_ordered_dict['#'] = {'name': '#', 'url': '#'}
    recursion_urls(None, pre_url, md.urlpatterns, url_ordered_dict)  # 递归去获取所有的路由
    return url_ordered_dict.values()

前端设计

前端代码已经开源,GitHub如下: nineaiyu/xadmin-client: xadmin-基于Django+vue3的rbac权限管理系统 (github.com)​​​​​​​q

前端是基于pure-admin二次开发的, 省去了前端开发,直接上手。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/710974.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

stable-diffusion使用openpose报错

依据教程 &#xff1a; https://post.smzdm.com/p/awz2l2xg/ 使用 stable-diffusion教学之ControlNetlora换脸 报错&#xff1a; urllib.error.URLError: <urlopen error [WinError 10054] 远程主机强迫关闭了一个现有的连接。> File "E:\ai\sd-webui-aki-v4\ext…

【数据挖掘】时间序列教程【五】

(说明:本文接上回:【数据挖掘】时间序列教程【四】_无水先生的博客-CSDN博客) 上面介绍的傅里叶变换的问题在于,无论是正弦/余弦回归模型形式还是复指数形式,它都需要 操作以计算所有傅里叶系数。有n 数据点和有n/2 可以计算傅里叶系数的频率。每个频率系…

Springboot3新特性异常信息ProblemDetail详解

环境&#xff1a;Springboot3.0.5 概述 RFC 7807定义了为HTTP响应中错误的可读详细信息&#xff0c;以避免需要为HTTP API定义新的错误响应格式。HTTP [RFC7230]状态码有时不足以传达关于错误的足够信息。 RFC 7807 定义了简单的JSON[RFC7159]和XML[W3C.REC-XML-20081126]文…

7.MHA高可用配置及故障切换

文章目录 MHA高可用配置及故障切换MHA概念实验配置时间同步与主从复制安装MHA服务SSH免交互认证验证MHA服务是否开启启动服务 故障模拟恢复故障过程 MHA高可用配置及故障切换 MHA概念 MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切…

计网实验第四章:IP

问题集1&#xff1a; 1.192.168.31.7 2. 上层协议为ICMP&#xff0c;并且其字段值为1 3. 20字节 56字节 - 20字节 36字节 解释&#xff1a;如图所示 4. 这个报文段没有分段发送 原因如图&#xff1a;按照下图所示 标志位显示没有更多的分段。 5. 同一地址发送的这两个…

1.计算机是如何工作的(下)

文章目录 4.编程语言&#xff08;Program Language&#xff09;4.1程序&#xff08;Program&#xff09;4.2早期编程4.3编程语言发展 5.操作系统&#xff08;Operating System&#xff09;5.1操作系统的定位5.2什么是进程/任务&#xff08;Process/Task&#xff09;5.3进程控制…

[LangChain]简介快速入门

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;人工智能。 目录 1、简介2、快速入门2.1、LLMs2.2、聊天模型2.3、提示模板2.4、链2.5、代理2.6、内存 1、简介 …

1758_C语言通过预处理的eror输出异常信息

全部学习汇总&#xff1a; GreyZhang/c_basic: little bits of c. (github.com) 这个功能我一直没有使用过&#xff0c;能够想到它完全是因为之前从某些代码中看了一眼。或许&#xff0c;这就是我跟这个小小知识点的缘分。 最近想处理一个可以适配多种情况的程序&#xff0c;…

领域驱动设计(DDD,Domain-Driven Design)

领域驱动设计 前言正文领域驱动设计基本概念什么是领域模型&#xff1f;什么是领域服务&#xff08;Domain Service&#xff09;&#xff1f;什么是领域事件&#xff1f; 秒杀项目中的领域分析一、秒杀活动领域设计秒杀活动领域模型领域服务领域事件 二、秒杀品领域设计领域模型…

开源自动化测试框架介绍

开源自动化测试框架介绍 一、Junit&#xff08;白盒测试、API自动化、UI自动化&#xff09;【官网】【简介】【使用场景】 二、Selenium&#xff08;Web自动化、爬虫&#xff09;【官网】【简介】【使用场景】 三、TestNG&#xff08;白盒测试、API自动化、UI自动化&#xff09…

Linux文件系统架构和共享文件方法

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来聊聊 Linux文件系统架构和共享文件方法。 在Linux环境中使用文件和目录是工作中不可回避的环节。当然&#xff0c;在我的博客里成立windows程序员看linux这个专题&#xff0c;主要还是因为微软也发布了…

LwIP系列(4):ARP协详解

前言 对于应用程序而言&#xff0c;我们与其他设备、服务通信&#xff0c;主要通过域名、IP进行通信&#xff0c;而以太网底层驱动&#xff0c;最终是通过MAC地址来表示设备的唯一标识&#xff0c;即IP是逻辑地址&#xff0c;并不是物理地址。在上一篇文章中&#xff0c;我们也…

【ArcGIS Pro二次开发】(45):手搓一个工具执行进度框

我在之前做的工具中&#xff0c;UI这部分基本没怎么深入&#xff0c;都是直接用的现成的控件。 其中有一个问题比较突出&#xff0c;就是没有工具执行的进度框提示。曾经也用过系统自带的信息提示框和进度条&#xff0c;但太简陋&#xff0c;确实不好用。于是就想抄一个进度框…

Linux 读文件 - readahead预读算法

顺序读场景 intmain{charc[ 4096];intin -1;in open( "news.txt", O_RDONLY);intindex 0;while(read(in, &c, 4096) 4096){printf( "index: %d,len: %ld.\n",index, strlen(c));memset(c, 0, sizeof(c));index;} 数据结构 /** Track a single fi…

CentOS7 静默方式安装 Oracle19C

CentOS7 静默方式安装 Oracle19C 操作系统&#xff1a;CentOS7 Oracle&#xff1a; 19C 安装常用工具和依赖 yum -y install vim tar net-tools wget perl python3 readline* deltarpm python-deltarpm \zip unzip bc compat-libcap1* compat-libcap* binutils compat-libstdc…

最近的感悟与总结

目录 一、判别填鸭、与被填鸭的思考讲解人&#xff1a;听者&#xff1a; 二、最近感悟&#xff1a;三、再来三道数学题吧&#xff1a;四、总结 一、判别填鸭、与被填鸭的思考 讲解人&#xff1a; 1.是否在讲解过程中增加了知识认识的维度&#xff1f;(具体是什么&#xff0c;…

08_Linux按键输入

目录 Linux下按键驱动原理 修改设备树文件 添加KEY设备节点 按键驱动程序编写 编写测试APP 运行测试 Linux下按键驱动原理 按键驱动和LED驱动原理上来讲基本都是一样的,都是操作GPIO,只不过一个是读取GPIO 的高低电平,一个是从GPIO输出高低电平。实现按键输入,在驱动程序…

nginx的安装与自启动配置

1. nginx源码下载 nginx源码下载 2. nginx编译安装 2.1 解压安装包 tar -zxvf nginx-1.24.0.tar.gz2.2 编译安装 cd nginx-1.24.0 ./configure make make install执行./configure时可能出现如下的error&#xff0c;需要安装依赖库&#xff1a; 缺少pcre库 下载pcre安装包…

链码的安装、实例化、查询、调用

目录 1、首先保证网络已经处于启动状态 2、进入CLI容器 3、检查当前节点已经加入到哪些通道中&#xff08;刚进来&#xff0c;默认是 peer0.example.com&#xff09; 链码的安装 1、检查通道名称是否设置正确 2、使用install安装链码 3、实例化链码 4、查詢链码 发起交易 …

English Learning - L3 作业打卡 Lesson7 Day52 2023.6.27 周二

English Learning - L3 作业打卡 Lesson7 Day52 2023.6.27 周二 引言&#x1f349;句1: And that is when it dawned on me that I didn’t have to be 5,5 ft. anymore.成分划分弱读连读爆破语调 &#x1f349;句2: I could be as tall as I wanted, or as short as I wanted …