django自定义rbac权限组件(二级菜单)

一、目录结构

 

二、表结构设计

model.py

from django.db import models

# Create your models here.


class Menu(models.Model):
    """菜单表 一级菜单"""
    title = models.CharField(max_length=32)
    icon = models.CharField(max_length=64, null=True, blank=True, verbose_name='图标')

    def __str__(self):
        return self.title

class Permission(models.Model):
    """
    权限表
    可以做二级菜单的权限   menu 关联 菜单表
    不可以做菜单的权限    menu=null
    """
    url = models.CharField(max_length=32, verbose_name='权限')
    title = models.CharField(max_length=32, verbose_name='标题')
    menu = models.ForeignKey("Menu",null=True, blank=True, verbose_name="所属菜单",on_delete=models.CASCADE)

    class Meta:
        # 这个选项是指定,模型的复数形式是什么,比如:
        # verbose_name_plural = "学校"
        # 如果不指定Django会自动在模型名称后加一个’s’
        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('Permission', verbose_name='角色拥有的权限',blank=True)

    def __str__(self):
        return self.name



class User(models.Model):
    """
    用户表
    """
    name = models.CharField(max_length=32, verbose_name='名称')
    password = models.CharField(max_length=32, verbose_name='密码')
    roles = models.ManyToManyField('Role', verbose_name='用户拥有的角色',blank=True)

    def __str__(self):
        return self.name

三、权限信息初始化

用户登陆成功后保留权限信息与菜单信息

service.permission.py

from django.conf import settings


def init_permisson(request, obj):
    """
        权限信息的初识化
        保存权限和菜单的信息
        :param request:
        :param obj:
        :return:
     """
    # 登陆成功,保存权限的信息(可能存在创建了角色没有分配权限,有的用户拥有多个角色权限重复的要去重.distinct())
    ret = obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                        'permissions__title',
                                                                        'permissions__menu__title',
                                                                        'permissions__menu__icon',
                                                                        'permissions__menu_id'
                                                                        ).distinct()

    # 存放权限信息
    permission_list = []
    # 存放菜单信息
    menu_dict = {}
    for item in ret:
        # 将所有的权限信息添加到permission_list
        permission_list.append({'url': item['permissions__url']})

        # 构造菜单的数据结构
        menu_id = item.get('permissions__menu_id')

        # 表示当前的权限是不做菜单的权限
        if not menu_id:
            continue

        # 可以做菜单的权限
        if menu_id not in menu_dict:
            menu_dict[menu_id] = {
                'title': item['permissions__title'],  # 一级菜单标题
                'icon': item['permissions__menu__icon'],
                'children': [
                    {'title': item['permissions__menu__title'], 'url': item['permissions__url']},
                ]
            }
        else:
            menu_dict[menu_id]['children'].append(
                {'title': item['permissions__menu__title'], 'url': item['permissions__url']})

    # print(menu_dict)
    # 保留权限信息到session(因为session可以存到内存中,提高工作效率)中
    request.session[settings.PERMISSION_SESSION_KEY] = permission_list

    # 保存菜单信息
    request.session[settings.PERMISSION_MENU_KEY] = menu_dict

四、中间件中权限校验

菜单数据结构构造

注意构造菜单的数据结构,将查询出的元数据构造为分级的数据结构。

# 元数据
data = [{
    'permissions__url': '/customer/list/',
    'permissions__title': '客户列表',
    'permissions__menu__title': '信息列表',
    'permissions__menu__icon': 'fa-code-fork',
    'permissions__menu_id': 1
},
    {
        'permissions__url': '/customer/list/',
        'permissions__title': '用户列表',
        'permissions__menu__title': '信息列表',
        'permissions__menu__icon': 'fa-code-fork',
        'permissions__menu_id': 1
    }, {
        'permissions__url': '/customer/add/',
        'permissions__title': '增加客户',
        'permissions__menu__title': None,
        'permissions__menu__icon': None,
        'permissions__menu_id': None
    }, {
        'permissions__url': '/customer/edit/(\\d+)/',
        'permissions__title': '编辑客户',
        'permissions__menu__title': None,
        'permissions__menu__icon': None,
        'permissions__menu_id': None
    }]
# 目标数据
{ 
  1:{
      'title':'信息列表',
      'icon':'fa-code-fork',
    'children': [
        {'title': '客户列表','url':'/customer/list/ },
        {'title': '用户列表','url':'/customer/list/ }
    ]
      
  }

}

middlewares.rbac.py

from django.conf import settings


def init_permisson(request, obj):
    """
        权限信息的初识化
        保存权限和菜单的信息
        :param request:
        :param obj:
        :return:
     """
    # 登陆成功,保存权限的信息(可能存在创建了角色没有分配权限,有的用户拥有多个角色权限重复的要去重.distinct())
    ret = obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                        'permissions__title',
                                                                        'permissions__menu__title',
                                                                        'permissions__menu__icon',
                                                                        'permissions__menu_id'
                                                                        ).distinct()

    # 存放权限信息
    permission_list = []
    # 存放菜单信息
    menu_dict = {}
    for item in ret:
        # 将所有的权限信息添加到permission_list
        permission_list.append({'url': item['permissions__url']})

        # 构造菜单的数据结构
        menu_id = item.get('permissions__menu_id')

        # 表示当前的权限是不做菜单的权限
        if not menu_id:
            continue

        # 可以做菜单的权限
        if menu_id not in menu_dict:
            menu_dict[menu_id] = {
                'title': item['permissions__title'],  # 一级菜单标题
                'icon': item['permissions__menu__icon'],
                'children': [
                    {'title': item['permissions__menu__title'], 'url': item['permissions__url']},
                ]
            }
        else:
            menu_dict[menu_id]['children'].append(
                {'title': item['permissions__menu__title'], 'url': item['permissions__url']})

    # print(menu_dict)
    # 保留权限信息到session(因为session可以存到内存中,提高工作效率)中
    request.session[settings.PERMISSION_SESSION_KEY] = permission_list

    # 保存菜单信息
    request.session[settings.PERMISSION_MENU_KEY] = menu_dict

五、自定义inclusion_tag

用于定义html片段,实现动态数据传入。

文件包必须叫templatetags

templatetags.rbac.py

from django import template
from django.conf import settings
import re

register = template.Library()


@register.inclusion_tag('rbac/menu.html')
def menu(request):
    # # 取到存在session 里的菜单权限信息信息(一级菜单时)
    # menu_list = request.session.get(settings.PERMISSION_MENU_KEY)
    #
    # for item in menu_list:
    #     # 正则匹配当前路径
    #     if re.match('^{}$'.format(item['url']), request.path_info):
    #         # 添加一个点击样式
    #         item['class'] = 'active'
    #         break
    # return {"menu_list": menu_list}

    # 二级菜单时
    menu_dict = request.session.get(settings.PERMISSION_MENU_KEY)

    return {'menu_list': menu_dict.values()}

 注意:为了不把数据写死,便于维护,存在session中的权限相关配置写在setting中

# session中保留权限key
PERMISSION_SESSION_KEY = 'permissions'
# 保留菜单信息key
PERMISSION_MENU_KEY = 'menus'
# 白名单
WHITE_LIST = [
    r'^/login/$',
    r'^/reg/$',
    r'^/admin/.*',
]

在templates模板中应用菜单

html

   {% load rbac %}
{#            <!--应用inclusion_tag('rbac/menu.html')-->#}
            {% menu request %}

 

转载于:https://www.cnblogs.com/zwq-/p/10171124.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Django中,可以使用django-admin来创建自定义RBAC认证系统。以下是一些步骤: 1. 创建一个新的Django应用程序: ``` python manage.py startapp rbac ``` 2. 在rbac应用程序中创建一个新的文件夹,命名为“rbac”。 3. 在rbac文件夹中创建一个新的文件,命名为“middleware.py”。 4. 在middleware.py中编写一个自定义的认证中间件类,可以参考下面的示例代码: ``` from django.contrib.auth.models import User class RbacMiddleware(object): def process_request(self, request): user = request.user if user.is_authenticated(): user_role = user.groups.first() if user_role: permissions = user_role.permissions.all() request.user_permissions = [p.codename for p in permissions] ``` 该中间件类的作用是在请求处理之前对用户进行认证,并将该用户的权限存储在请求对象中。 5. 在settings.py中配置中间件: ``` MIDDLEWARE_CLASSES = ( # ... 'rbac.middleware.RbacMiddleware', # ... ) ``` 6. 创建一个新的文件夹,命名为“rbac_templates”。 7. 在rbac_templates文件夹中创建一个新的文件,命名为“base.html”。 8. 在base.html中编写一个自定义RBAC模板标签,可以参考下面的示例代码: ``` {% if perms.app_label.permission_name %} <!-- Display some content here --> {% endif %} ``` 该模板标签的作用是根据用户的权限显示或隐藏特定的内容。 9. 在需要进行RBAC认证的视图函数中使用模板标签,例如: ``` def my_view(request): return render(request, 'my_template.html', {}) ``` 10. 在my_template.html中使用自定义RBAC模板标签: ``` {% extends 'rbac_templates/base.html' %} {% block content %} {% if perms.app_label.permission_name %} <h1>Welcome to my page!</h1> {% else %} <p>You do not have permission to view this page.</p> {% endif %} {% endblock %} ``` 以上就是使用django-admin自定义RBAC认证的一些步骤。需要注意的是,这只是一个简单的示例,实际情况可能更加复杂,需要根据具体的应用场景进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值