本次是基于Django和vue實(shí)現(xiàn)
github源碼:nineaiyu/xadmin-server: xadmin-基于Django+vue3的rbac權(quán)限管理系統(tǒng) (github.com)
服務(wù)器設(shè)計(jì)及部分代碼?
權(quán)限控制的話,可以基于Django的permission進(jìn)行控制,并通過訪問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('權(quán)限不足')
else:
raise NotAuthenticated('未授權(quán)認(rèn)證')
因此,需要對menu表進(jìn)行設(shè)計(jì),由于涉及到了前端vue路由,因此,menu模型字段比較多,如下
class DbBaseModel(models.Model):
created_time = models.DateTimeField(auto_now_add=True, verbose_name="添加時(shí)間")
updated_time = models.DateTimeField(auto_now=True, verbose_name="更新時(shí)間")
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="菜單圖標(biāo)", max_length=256, null=True, blank=True)
r_svg_name = models.CharField(verbose_name="菜單右側(cè)額外圖標(biāo)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='開啟后,會(huì)保存該頁面的整體狀態(tài),刷新后會(huì)清空狀態(tài)')
frame_url = models.CharField(verbose_name="內(nèi)嵌的iframe鏈接地址", max_length=256, null=True, blank=True)
frame_loading = models.BooleanField(verbose_name="內(nèi)嵌的iframe頁面是否開啟首次加載動(dòng)畫", default=False)
transition_enter = models.CharField(verbose_name="當(dāng)前頁面進(jìn)場動(dòng)畫", max_length=256, null=True, blank=True)
transition_leave = models.CharField(verbose_name="當(dāng)前頁面離場動(dòng)畫", max_length=256, null=True, blank=True)
is_hidden_tag = models.BooleanField(verbose_name="當(dāng)前菜單名稱或自定義信息禁止添加到標(biāo)簽頁", default=False)
dynamic_level = models.IntegerField(verbose_name="顯示標(biāo)簽頁最大數(shù)量", default=1)
class Meta:
verbose_name = "菜單元數(shù)據(jù)"
verbose_name_plural = "菜單元數(shù)據(jù)"
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="父節(jié)點(diǎn)", null=True, blank=True)
menu_type_choices = ((0, '目錄'), (1, '菜單'), (2, '權(quán)限'))
menu_type = models.SmallIntegerField(choices=menu_type_choices, default=0, verbose_name="節(jié)點(diǎn)類型")
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="菜單元數(shù)據(jù)")
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表已經(jīng)設(shè)計(jì)完成,那么接下來就更簡單了,還需要一個(gè)獲取所有路由的方法,當(dāng)添加權(quán)限的時(shí)候,可以方便的選擇相應(yīng)的路由權(quán)限
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: 路由關(guān)系列表
: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路由中必須設(shè)置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): # 路由分發(fā),遞歸操作
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='/'):
"""
獲取項(xiàng)目中所有的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()
前端設(shè)計(jì)
前端代碼已經(jīng)開源,GitHub如下:?nineaiyu/xadmin-client: xadmin-基于Django+vue3的rbac權(quán)限管理系統(tǒng) (github.com)???????q
前端是基于pure-admin二次開發(fā)的, 省去了前端開發(fā),直接上手。
文章來源:http://www.zghlxwxcb.cn/news/detail-527253.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-527253.html
到了這里,關(guān)于Django+vue3權(quán)限菜單rabc設(shè)計(jì)和動(dòng)態(tài)路由的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!