zoukankan      html  css  js  c++  java
  • Django之权限管理

    一, 引入

    1.为什么要有权限?

    2.为什么要开发权限的组件?

    3.在web开发中,什么是权限?

    4.表结构的设计

    权限表

    ID URL
    1 /user_list/
    2 /customer_list/

    用户表

    ID USER_NAME
    1 root
    2 root 2

    角色/用户组表

    ID
    1 销售
    2 开发

    用户与角色的关系表

    ID USER_ID 角色ID
    1 1 1
    2 1 2
    3 2 1
    4 2 2

    角色与权限的关系表

    ID 角色ID 权限ID
    1 1 1
    2 1 2
    3 2 1
    4 2 2

    models:

    from django.db import models
    
    
    # 权限表
    class Permission(models.Model):
        url = models.CharField(max_length=108, verbose_name='权限')
    
    
    # 角色表
    class Role(models.Model):
        name = models.CharField(max_length=108, verbose_name='角色')
        permissions = models.ManyToManyField('Permission', verbose_name='角色所拥有的权限', related_name='roles')
    
    
    # 用户表
    class UserInfo(models.Model):
        username = models.CharField(max_length=32, verbose_name='用户名')
        password = models.CharField(max_length=32, verbose_name='密码')
        roles = models.ManyToManyField('Role', verbose_name='用户所拥有的角色', related_name='users')
    

    基本流程:

    二, admin的展示

    from django.contrib import admin
    from rbac import models
    
    # 配置类
    class PermissionAdmin(admin.ModelAdmin):
        # 展示
        list_display = ['title', 'url']
        # 可编辑
        list_editable = ['url']
    
    admin.site.register(models.Role)
    admin.site.register(models.Permission, admin_class=PermissionAdmin)
    admin.site.register(models.UserInfo)
    

    三, 记录登录状态与权限

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse, redirect, reverse
    from django.conf import settings
    import re
    
    def login(request):
        error = ''
        if request.method == 'POST':
            # 获取用户名和密码
            username = request.POST.get('username')
            password = request.POST.get('password')
            # 数据库校验用户名密码是否正确
            user_obj = models.UserInfo.objects.filter(username=username, password=password).first()
            if not user_obj:
                # 校验失败,返回登录页面
                error = '用户名或密码错误'
            else:
                # 登录成功
                # 查询当前用户的权限信息
                # permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
                permission = user_obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url').distinct()
                # 保存权限信息
                request.session['permission'] = list(permission)
                request.session['is_login'] = 1
                # 重定向去首页
                return redirect('index')
    
        return render(request, 'login.html', {'error': error})
    

    四, 中间件校验权限

    class Rbac(MiddlewareMixin):
    
        def process_request(self, request):
            # 获取当前访问的地址
            url = request.path_info
            # 白名单
            for i in settings.WHITE_LIST:
                if re.match(i, url):
                    return
            # 登陆状态的校验
            is_login = request.session.get('is_login')
            if not is_login:
                return redirect('login]')
            # 免认证校验
            for i in settings.PASS_AUTH_LIST:
                if re.match(i, url):
                    return
            # 获取权限信息
            permissions = request.session.get('permission')
            # 权限的校验
            for i in permissions:
                if re.match(r'^{}$'.format(i['permissions__url']), url):
                    return
                    # 拒绝请求
            return HttpResponse('没有访问权限,请联系管理员')
    
    # settings.py中
    # rbac 白名单
    WHITE_LIST = [
        r'^/admin/',
        r'^/login/$',
        r'^/register/$',
    ]
    
    # rabc 免认证
    PASS_AUTH_LIST =[
        r'^/index/$'
    ]
    

    五, 动态生成一级菜单

    首先规范化RBAC:

    在settings.py中配置
    PERMISSION_SESSION_KEY  session中记录权限的key
    MENU_SESSION_KEY        session中记录菜单信息的key
    LOGIN_SESSION_KEY       session中记录登录状态的key
    

    将相关template,static,服务等整理到rbac(app)内

    model的更改:

    # 权限表
    class Permission(models.Model):
        url = models.CharField(max_length=108, verbose_name='权限')
        title = models.CharField(max_length=108, verbose_name='标题')
        is_menu = models.BooleanField(default=False, choices=((True, '是'), (False, '否')), verbose_name='是否目录')
        icon = models.CharField(max_length=64, verbose_name='图标', null=True, blank=True)
    
        def __str__(self):
            return self.title
    

    session记录的更改:

    # 查询当前用户的权限信息
    # permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
    permission = user_obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                                    'permissions__title',
                                                                                    'permissions__is_menu',
                                                                                    'permissions__icon',
                                                                                    ).distinct()
    # 权限的列表
    permission_list = []
    # 菜单的列表
    menu_list = []
    
    for i in permission:
        permission_list.append({
            'url': i['permissions__url']
        })
        if i.get('permissions__is_menu'):
            menu_list.append({
                'title': i['permissions__title'],
                'icon': i['permissions__icon'],
                'url': i['permissions__url']
            })
    # 保存权限信息
    request.session[settings.PERMISSION_SESSION_KEY] = permission_list
    request.session[settings.LOGIN_SESSION_KEY] = True
    # 保存菜单信息
    request.session[settings.MENU_SESSION_KEY] = menu_list
    

    自定义inclusion_tag:

    // 插件 menu.html
    <div class="static-menu">
        {% for menu in menu_list %}
            <a href="{{ menu.url }}" class="{{ menu.class }}">
                <span class="icon-wrap"><i class="fa {{ menu.icon }}"></i></span> {{ menu.title }}</a>
        {% endfor %}
    </div>
    
    from django import template
    from django.conf import settings
    
    register = template.Library()
    
    @register.inclusion_tag('rbac/menu.html')
    def menu(request):
        menu_list = request.session.get(settings.MENU_SESSION_KEY)
        url = request.path_info
        for menu in menu_list:
            if menu.get('url') == url:
                menu['class'] = 'active'
        return {'menu_list': request.session.get(settings.MENU_SESSION_KEY)}
    

    六, 动态生成二级菜单

    model的更改:

    # 一级菜单表
    class Menu(models.Model):
        title = models.CharField(max_length=108, verbose_name='一级菜单标题')
        icon = models.CharField(max_length=64, verbose_name='图标', null=True, blank=True)
    
        def __str__(self):
            return self.title
    
    
    # 权限表(二级菜单)
    class Permission(models.Model):
        '''
        menu_id: 有menu_id表示当前的权限是二级菜单
                 没有menu_id表示当前的权限是普通权限
        '''
        url = models.CharField(max_length=108, verbose_name='权限')
        title = models.CharField(max_length=108, verbose_name='二级菜单标题')
        menu = models.ForeignKey('Menu', on_delete=models.CASCADE, verbose_name='一级菜单', null=True, blank=True)
    
        def __str__(self):
            return self.title
    

    session记录的更改:

    # 查询当前用户的权限信息
    # permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
    permission = user_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 i in permission:
        permission_list.append({'url': i.get('permissions__url')})
    
        menu_id = i.get('permissions__menu_id')
        if menu_id:
            menu_dict.setdefault(menu_id, {
                'title': i['permissions__menu__title'],
                'icon': i['permissions__menu__icon'],
                'children': []
            })
            menu_dict[menu_id]['children'].append(
                {
                    'title': i['permissions__title'],
                    'url': i['permissions__url']
                }
            )
    # 保存权限信息
    request.session[settings.PERMISSION_SESSION_KEY] = permission_list
    request.session[settings.LOGIN_SESSION_KEY] = True
    # 保存菜单信息
    request.session[settings.MENU_SESSION_KEY] = menu_dict
    

    自定义inclusion_tag:

    // 插件中 menu.html
    <div class="multi-menu">
        {% for menu_first in menu_list %}
            <div class="item">
                <div class="title">
                    <i class="fa {{ menu_first.icon }}"></i> {{ menu_first.title }}
                </div>
                <div class="body">
                    {% for menu_second in menu_first.children %}
                        <a class="{{ menu_second.class }}" href="{{ menu_second.url }}">{{ menu_second.title }}</a>
                    {% endfor %}
                </div>
            </div>
        {% endfor %}
    </div>
    
    # inclusion_tag
    @register.inclusion_tag('rbac/menu.html')
    def menu(request):
        menu_list = request.session.get(settings.MENU_SESSION_KEY).values()
        url = request.path_info
        for menu in menu_list:
            for i in menu.get('children'):
                if i.get('url') == url:
                    i['class'] = 'active'
        return {'menu_list': menu_list}
    

    七, 面包屑导航

    model的更改:

    # 一级菜单表
    class Menu(models.Model):
        title = models.CharField(max_length=108, verbose_name='一级菜单标题')
        icon = models.CharField(max_length=64, verbose_name='图标', null=True, blank=True)
        weight = models.IntegerField(default=1, verbose_name='权重') # 用于一级菜单排序
    
        def __str__(self):
            return self.title
    
    
    # 权限表(二级菜单)
    class Permission(models.Model):
        url = models.CharField(max_length=108, verbose_name='权限')
        title = models.CharField(max_length=108, verbose_name='二级菜单标题')
        menu = models.ForeignKey('Menu', on_delete=models.CASCADE, verbose_name='一级菜单', null=True, blank=True)
        parent = models.ForeignKey('self', on_delete=models.DO_NOTHING, verbose_name='父权限', null=True, blank=True)  # 用于区分二级权限和三级权限,生成面包屑导航
    
        def __str__(self):
            return self.title
    

    session记录的更改:

        # 查询当前用户的权限信息
        # permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
        permission = user_obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                                        'permissions__title',
                                                                                        'permissions__id',
                                                                                        'permissions__parent_id',
                                                                                        'permissions__menu__title',
                                                                                        'permissions__menu__icon',
                                                                                        'permissions__menu__weight',
                                                                                        'permissions__menu_id',
                                                                                        ).distinct()
        # 权限的字典
        permission_dict = {}
        # 菜单的字典
        menu_dict = {}
    
        for i in permission:
            permission_dict[i.get('permissions__id')] = {
                'url': i.get('permissions__url'),
                'title': i.get('permissions__title'),
                'id': i.get('permissions__id'),
                'parent_id': i.get('permissions__parent_id')
    
            }
    
            menu_id = i.get('permissions__menu_id')
            if menu_id:
                menu_dict.setdefault(menu_id, {
                    'title': i['permissions__menu__title'],
                    'icon': i['permissions__menu__icon'],
                    'weight': i['permissions__menu__weight'],
                    'children': []
                })
                menu_dict[menu_id]['children'].append(
                    {
                        'title': i['permissions__title'],
                        'url': i['permissions__url'],
                        'id': i['permissions__id'],
                    }
                )
        # 保存权限信息
        request.session[settings.PERMISSION_SESSION_KEY] = permission_dict
        request.session[settings.LOGIN_SESSION_KEY] = True
        # 保存菜单信息
        request.session[settings.MENU_SESSION_KEY] = menu_dict
    
    # 此时session记录信息数据格式
    # 注意: 存入session中时经过json序列化,字典的key中的数字会转换为字符串
    # 权限信息字典
    {
    	1: {
    		'url': '/customer/list/',
    		'title': '客户列表',
    		'id': 1,
    		'parent_id': None
    	},
    	2: {
    		'url': '/customer/add/',
    		'title': '添加客户',
    		'id': 2,
    		'parent_id': 1
    	},
    	3: {
    		'url': '/customer/edit/(?P<cid>\d+)/',
    		'title': '编辑客户',
    		'id': 3,
    		'parent_id': 1
    	},
    	4: {
    		'url': '/customer/del/(?P<cid>\d+)/',
    		'title': '删除客户',
    		'id': 4,
    		'parent_id': 1
    	},
    	5: {
    		'url': '/payment/list/',
    		'title': '缴费列表',
    		'id': 5,
    		'parent_id': None
    	},
    	6: {
    		'url': '/payment/add/',
    		'title': '添加缴费',
    		'id': 6,
    		'parent_id': 5
    	},
    	7: {
    		'url': '/payment/edit/(?P<pid>\d+)/',
    		'title': '编辑缴费',
    		'id': 7,
    		'parent_id': 5
    	},
    	8: {
    		'url': '/payment/del/(?P<pid>\d+)/',
    		'title': '删除缴费',
    		'id': 8,
    		'parent_id': 5
    	}
    }
    
    # 菜单信息字典
    {
    	1: {
    		'title': '客户管理',
    		'icon': 'fa-address-book',
    		'weight': 10,
    		'children': [{
    			'title': '客户列表',
    			'url': '/customer/list/',
    			'id': 1
    		}]
    	},
    	2: {
    		'title': '财务管理',
    		'icon': 'fa-money',
    		'weight': 1,
    		'children': [{
    			'title': '缴费列表',
    			'url': '/payment/list/',
    			'id': 5
    		}]
    	}
    }
    

    中间件的更改:

    class Rbac(MiddlewareMixin):
    
        def process_request(self, request):
            # 获取当前访问的地址
            url = request.path_info
            # 初始化current_menu_id
            request.current_menu_id = None
            # 初始化导航列表
            request.breadcrumb_list = [
                {'title': '首页', 'url': '/index/'}
            ]
            # 白名单
            for i in settings.WHITE_LIST:
                if re.match(i, url):
                    return
            # 登陆状态的校验
            is_login = request.session.get(settings.LOGIN_SESSION_KEY)
            if not is_login:
                return redirect('login')
            # 免认证校验
            for i in settings.PASS_AUTH_LIST:
                if re.match(i, url):
                    return
            # 获取权限信息
            permissions = request.session.get(settings.PERMISSION_SESSION_KEY)
            # 权限的校验
            for i in permissions.values():
                # i 权限  父权限  子权限
                if re.match(fr'^{i["url"]}$', url):
                    menu_id = i.get('parent_id')
                    if not menu_id:
                        # 当前访问的权限是父权限(二级菜单)
                        menu_id = i.get('id')
                        request.breadcrumb_list.append({
                            'title': i['title'],
                            'url': i['url']
                        })
                    else:
                        # 当前访问的权限是子权限
                        parent_permission = permissions[str(menu_id)]
                        request.breadcrumb_list.append({
                            'title': parent_permission['title'],
                            'url': parent_permission['url'],
                        })
                        request.breadcrumb_list.append({
                            'title': i['title'],
                            'url': i['url'],
                        })
                    request.current_menu_id = menu_id
                    return
                    # 拒绝请求
            return render(request, 'rbac/403.html')
    

    自定义inclusion_tag:

    @register.inclusion_tag('rbac/menu.html')
    def menu(request):
        menu_list = request.session.get(settings.MENU_SESSION_KEY).values()
        od_menu_list = sorted(menu_list, key=lambda x: x['weight'], reverse=True)
        for menu in od_menu_list:
            menu['class'] = 'hidden'
            for i in menu.get('children'):
                if i.get('id') == request.current_menu_id:
                    i['class'] = 'active'
                    menu['class'] = ''
                    break
        return {'menu_list': od_menu_list}
    
    // 插件  menu.html
    <div class="multi-menu">
        {% for menu_first in menu_list %}
            <div class="item">
                <div class="title">
                    <i class="fa {{ menu_first.icon }}"></i> {{ menu_first.title }}
                </div>
                <div class="body {{ menu_first.class }}">
                    {% for menu_second in menu_first.children %}
                        <a class="{{ menu_second.class }}" href="{{ menu_second.url }}">{{ menu_second.title }}</a>
                    {% endfor %}
                </div>
            </div>
        {% endfor %}
    </div>
    --------------------------------------------------------------
    // breadcrumb.html
    <ol class="breadcrumb no-radius no-margin" style="border-bottom: 1px solid #ddd;">
        {% for breadcrumb in breadcrumb_list %}
            {% if forloop.last %}
                <li class="active">{{ breadcrumb.title }}</li>
            {% else %}
                <li><a href="{{ breadcrumb.url }}">{{ breadcrumb.title }}</a></li>
            {% endif %}
        {% endfor %}
    </ol>
    

    八, 权限控制到按钮级别

    model的更改:

    # 权限表(二级菜单)
    class Permission(models.Model):
        '''
        name: 权限控制到按钮级别,判断是否有这个权限
        '''
        url = models.CharField(max_length=108, verbose_name='权限')
        name = models.CharField(max_length=108, verbose_name='url别名', unique=True)
        title = models.CharField(max_length=108, verbose_name='二级菜单标题')
        menu = models.ForeignKey('Menu', on_delete=models.CASCADE, verbose_name='一级菜单', null=True, blank=True)
        parent = models.ForeignKey('self', on_delete=models.DO_NOTHING, verbose_name='父权限', null=True, blank=True)
    
        def __str__(self):
            return self.title
    

    session记录的更改:

    # 查询当前用户的权限信息
        # permission = models.Permission.objects.filter(roles__users=user_obj).values('url').distinct()
        permission = user_obj.roles.all().filter(permissions__url__isnull=False).values('permissions__url',
                                                                                        'permissions__title',
                                                                                        'permissions__id',
                                                                                        'permissions__name',
                                                                                        'permissions__parent_id',
                                                                                        'permissions__parent__name',
                                                                                        'permissions__menu__title',
                                                                                        'permissions__menu__icon',
                                                                                        'permissions__menu__weight',
                                                                                        'permissions__menu_id',
                                                                                        ).distinct()
        # 权限的字典
        permission_dict = {}
        # 菜单的字典
        menu_dict = {}
        for i in permission:
            permission_dict[i.get('permissions__name')] = {
                'url': i.get('permissions__url'),
                'title': i.get('permissions__title'),
                'id': i.get('permissions__id'),
                'parent_id': i.get('permissions__parent_id'),
                'parent_name': i.get('permissions__parent__name'),
            }
            menu_id = i.get('permissions__menu_id')
            if menu_id:
                menu_dict.setdefault(menu_id, {
                    'title': i['permissions__menu__title'],
                    'icon': i['permissions__menu__icon'],
                    'weight': i['permissions__menu__weight'],
                    'children': []
                })
                menu_dict[menu_id]['children'].append(
                    {
                        'title': i['permissions__title'],
                        'url': i['permissions__url'],
                        'id': i['permissions__id'],
                    }
                )
        # 保存权限信息
        request.session[settings.PERMISSION_SESSION_KEY] = permission_dict
        request.session[settings.LOGIN_SESSION_KEY] = True
        # 保存菜单信息
        request.session[settings.MENU_SESSION_KEY] = menu_dict
    

    中间件:

    # 获取权限信息
    permissions = request.session.get(settings.PERMISSION_SESSION_KEY)
    # 权限的校验
    for i in permissions.values():
        # i权限  父权限  子权限
        if re.match(fr'^{i["url"]}$', url):
            menu_id = i.get('parent_id')
            if not menu_id:
                # 当前访问的权限是父权限(二级菜单)
                menu_id = i.get('id')
                request.breadcrumb_list.append({
                    'title': i['title'],
                    'url': i['url']
                })
            else:
                # 当前访问的权限是子权限
                parent_name = i.get('parent_name')
                parent_permission = permissions[parent_name]
                request.breadcrumb_list.append({
                    'title': parent_permission['title'],
                    'url': parent_permission['url'],
                })
                request.breadcrumb_list.append({
                    'title': i['title'],
                    'url': i['url'],
                })
            request.current_menu_id = menu_id
            return
            # 拒绝请求
    return render(request, 'rbac/403.html')
    

    自定义tags:

    @register.inclusion_tag('rbac/menu.html')
    def menu(request):
        menu_list = request.session.get(settings.MENU_SESSION_KEY).values()
        od_menu_list = sorted(menu_list, key=lambda x: x['weight'], reverse=True)
        for menu in od_menu_list:
            menu['class'] = 'hidden'
            for i in menu.get('children'):
                if i.get('id') == request.current_menu_id:
                    i['class'] = 'active'
                    menu['class'] = ''
                    break
        return {'menu_list': od_menu_list}
    
    
    @register.inclusion_tag('rbac/breadcrumb.html')
    def breadcrumb(request):
        return {
            'breadcrumb_list': request.breadcrumb_list
        }
    
    
    @register.filter
    def has_permission(request, name):
        permission = request.session.get(settings.PERMISSION_SESSION_KEY)
        if name in permission:
            return True
    

    模板中使用:

    {% if request|has_permission:'customer_add' %}
        <a class="btn btn-default" href="{% url 'customer_add' %}">
            <i class="fa fa-plus-square" aria-hidden="true"></i> 添加客户
        </a>
    {% endif %}
    

    九, 权限管理

    # routes.py中
    from django.conf import settings
    from django.utils.module_loading import import_string
    from django.urls import RegexURLResolver, RegexURLPattern
    from collections import OrderedDict
    
    
    def recursion_urls(pre_namespace, pre_url, urlpatterns, url_ordered_dict):
    
        for item in urlpatterns:
            if isinstance(item, RegexURLResolver):
                if pre_namespace:
                    if item.namespace:
                        namespace = "%s:%s" % (pre_namespace, item.namespace,)
                    else:
                        namespace = pre_namespace
                else:
                    if item.namespace:
                        namespace = item.namespace
                    else:
                        namespace = None
    
                " None   /^  "
                recursion_urls(namespace, pre_url + item.regex.pattern, item.url_patterns, url_ordered_dict)
            else:
    
                if pre_namespace:
                    name = "%s:%s" % (pre_namespace, item.name,)
                else:
                    name = item.name
                if not item.name:
                    raise Exception('URL路由中必须设置name属性')
                """
                /^^login/$    /login/ 
                """
                url = pre_url + item._regex
                url_ordered_dict[name] = {'name': name, 'url': url.replace('^', '').replace('$', '')}
    
    
    def get_all_url_dict(ignore_namespace_list=None):
        """
        获取路由中
        :return:
        """
        ignore_list = ignore_namespace_list or []
        url_ordered_dict = OrderedDict()
    
        md = import_string(settings.ROOT_URLCONF)  # 根据路径的字符串 导入模块
        urlpatterns = []
        
        for item in md.urlpatterns:
            if isinstance(item, RegexURLResolver) and item.namespace in ignore_list:
                continue
            urlpatterns.append(item)
        recursion_urls(None, "/", urlpatterns, url_ordered_dict)
        return url_ordered_dict
    
    
    # views.py
    from django.shortcuts import render, redirect, reverse, HttpResponse
    from django.views import View
    from rbac import models
    from django.db.models import Q
    from rbac.forms import RoleForm
    from rbac.forms import MenuForm
    from rbac.forms import PermissionForm
    from rbac.forms import MultiPermissionForm
    from django.forms import modelformset_factory, formset_factory
    from rbac.service.routes import get_all_url_dict
    
    
    # 展示角色
    class RoleList(View):
    
        def get(self, request):
            all_role = models.Role.objects.all()
            return render(request, 'rbac/role_list.html', {
                'all_role': all_role
            })
    
    
    # 新增编辑角色
    class RoleChange(View):
        def get(self, request, role_id=None, *args, **kwargs):
            role_obj = models.Role.objects.filter(pk=role_id).first()
            form_obj = RoleForm(instance=role_obj)
            return render(request, 'rbac/forms.html', {
                'form_obj': form_obj,
            })
    
        def post(self, request, role_id=None, *args, **kwargs):
            role_obj = models.Role.objects.filter(pk=role_id).first()
            form_obj = RoleForm(instance=role_obj, data=request.POST)
            if form_obj.is_valid():
                form_obj.save()
                return redirect('rbac:role_list')
            return render(request, 'rbac/forms.html', {
                'form_obj': form_obj,
            })
    
    
    # 展示权限信息
    class MenuList(View):
        def get(self, request):
            mid = request.GET.get('mid')
            if not mid:
                all_permission = models.Permission.objects.all()
            else:
                all_permission = models.Permission.objects.filter(Q(menu_id=mid) | Q(parent__menu_id=mid))
            # all_permission = all_permission.values('id', 'title', 'name', 'url', 'menu_id', 'menu__title', 'parent_id')
            permission_dict = {}
            for i in all_permission:
                menu_id = i.menu_id
                id = i.pk
                if menu_id:
                    i.children = []
                    permission_dict[id] = i
            for i in all_permission:
                parent_id = i.parent_id
                if parent_id:
                    permission_dict[parent_id].children.append(i)
            all_menu = models.Menu.objects.all()
            return render(request, 'rbac/menu_list.html', {
                'all_menu': all_menu,
                'all_permission': permission_dict.values(),
                'mid': mid,
            })
    
    
    # 新增编辑菜单
    class MenuChange(View):
        def get(self, request, menu_id=None, *args, **kwargs):
            menu_obj = models.Menu.objects.filter(pk=menu_id).first()
            form_obj = MenuForm(instance=menu_obj)
            return render(request, 'rbac/menu_form.html', {
                'form_obj': form_obj,
            })
    
        def post(self, request, menu_id=None, *args, **kwargs):
            menu_obj = models.Menu.objects.filter(pk=menu_id).first()
            form_obj = MenuForm(instance=menu_obj, data=request.POST)
            if form_obj.is_valid():
                form_obj.save()
                return redirect('rbac:menu_list')
            return render(request, 'rbac/menu_form.html', {
                'form_obj': form_obj,
            })
    
    
    # 新增编辑权限
    class PermissionChange(View):
        def get(self, request, permission_id=None, *args, **kwargs):
            permission_obj = models.Permission.objects.filter(pk=permission_id).first()
            form_obj = PermissionForm(instance=permission_obj)
            return render(request, 'rbac/menu_form.html', {
                'form_obj': form_obj,
            })
    
        def post(self, request, permission_id=None, *args, **kwargs):
            permission_obj = models.Permission.objects.filter(pk=permission_id).first()
            form_obj = PermissionForm(instance=permission_obj, data=request.POST)
            if form_obj.is_valid():
                form_obj.save()
                return redirect('rbac:menu_list')
            return render(request, 'rbac/forms.html', {
                'form_obj': form_obj,
            })
    
    
    # 删除
    class Delete(View):
        def get(self, request, table, pk):
            model = getattr(models, table.capitalize())
            if not model:
                return HttpResponse('非法操作')
            obj = model.objects.filter(pk=pk).first()
            if not obj:
                return HttpResponse('非法操作')
            obj.delete()
            return redirect(request.META['HTTP_REFERER'])
    
    
    def multi_permissions(request):
        """
        批量操作权限
        :param request:
        :return:
        """
        post_type = request.GET.get('type')
        # 编辑  删除
        FormSet = modelformset_factory(models.Permission, MultiPermissionForm, extra=0)
        # 新增
        AddFormSet = formset_factory(MultiPermissionForm, extra=0)
        # 数据库所有的权限
        permissions = models.Permission.objects.all()
        # 路由系统的所有的url 权限
        router_dict = get_all_url_dict(ignore_namespace_list=['admin'])
    
        # 数据库权限的name的集合
        permissions_name_set = set([i.name for i in permissions])
        # 路由系统中权限的name的集合
        router_name_set = set(router_dict.keys())
    
        add_name_set = router_name_set - permissions_name_set
        add_formset = AddFormSet(initial=[row for name, row in router_dict.items() if name in add_name_set])
    
        if request.method == 'POST' and post_type == 'add':
            add_formset = AddFormSet(request.POST)
            if add_formset.is_valid():
                permission_obj_list = [models.Permission(**i) for i in add_formset.cleaned_data]
                query_list = models.Permission.objects.bulk_create(permission_obj_list)
                add_formset = AddFormSet()
                for i in query_list:
                    permissions_name_set.add(i.name)
    
        del_name_set = permissions_name_set - router_name_set
        del_formset = FormSet(queryset=models.Permission.objects.filter(name__in=del_name_set))
    
        update_name_set = permissions_name_set & router_name_set
        update_formset = FormSet(queryset=models.Permission.objects.filter(name__in=update_name_set))
    
        if request.method == 'POST' and post_type == 'update':
            update_formset = FormSet(request.POST)
            if update_formset.is_valid():
                update_formset.save()
                update_formset = FormSet(queryset=models.Permission.objects.filter(name__in=update_name_set))
    
        return render(
            request,
            'rbac/multi_permissions.html',
            {
                'del_formset': del_formset,
                'update_formset': update_formset,
                'add_formset': add_formset,
            }
        )
    
    
    def distribute_permissions(request):
        """
        分配权限
        :param request:
        :return:
        """
        uid = request.GET.get('uid')
        rid = request.GET.get('rid')
    
        if request.method == 'POST' and request.POST.get('postType') == 'role':
            user = models.UserInfo.objects.filter(id=uid).first()
            if not user:
                return HttpResponse('用户不存在')
            user.roles.set(request.POST.getlist('roles'))
    
        if request.method == 'POST' and request.POST.get('postType') == 'permission' and rid:
            role = models.Role.objects.filter(id=rid).first()
            if not role:
                return HttpResponse('角色不存在')
            role.permissions.set(request.POST.getlist('permissions'))
    
        # 所有的用户
        user_list = models.UserInfo.objects.all()
        # 用户所拥有的角色 id
        user_has_roles = models.UserInfo.objects.filter(id=uid).values('id', 'roles')
    
        # 用户所拥有的角色id   {角色的id:None }
        user_has_roles_dict = {item['roles']: None for item in user_has_roles}
        # 所有的角色
        role_list = models.Role.objects.all()
    
        if rid:
            role_has_permissions = models.Role.objects.filter(id=rid, permissions__id__isnull=False).values('id',
                                                                                                            'permissions')
        elif uid and not rid:
            user = models.UserInfo.objects.filter(id=uid).first()
            if not user:
                return HttpResponse('用户不存在')
            role_has_permissions = user.roles.filter(permissions__id__isnull=False).values('id', 'permissions')
        else:
            role_has_permissions = []
    
        # 用户 或者 角色所拥有的权限
        role_has_permissions_dict = {item['permissions']: None for item in role_has_permissions}
    
        all_menu_list = []
    
        queryset = models.Menu.objects.values('id', 'title')  # [ { id  title } ]
        menu_dict = {}
    
        for item in queryset:
            # { id  title  children:[]  }
            item['children'] = []
            menu_dict[item['id']] = item
            all_menu_list.append(item)
    
        other = {'id': None, 'title': '其他', 'children': []}
        all_menu_list.append(other)
        menu_dict[None] = other
    
        root_permission = models.Permission.objects.filter(menu__isnull=False).values('id', 'title', 'menu_id')
        root_permission_dict = {}
        for per in root_permission:
            # { id  title menu_id   'children':[] }
            per['children'] = []
            nid = per['id']
            menu_id = per['menu_id']
            root_permission_dict[nid] = per
            menu_dict[menu_id]['children'].append(per)
    
        node_permission = models.Permission.objects.filter(menu__isnull=True).values('id', 'title', 'parent_id')
    
        for per in node_permission:
            # {  id  title parent_id  }
            pid = per['parent_id']
            if not pid:
                menu_dict[None]['children'].append(per)
                continue
            root_permission_dict[pid]['children'].append(per)
    
        return render(
            request,
            'rbac/distribute_permissions.html',
            {
                'user_list': user_list,  # 所有的用户
                'role_list': role_list,  # 所有的角色
                'user_has_roles_dict': user_has_roles_dict,  # 用户所拥有的角色
                'role_has_permissions_dict': role_has_permissions_dict,  # 角色拥有的权限
                'all_menu_list': all_menu_list,  # 菜单列表
                'uid': uid,
                'rid': rid
            }
        )
    
    
  • 相关阅读:
    AES对称加密和解密
    Akka并发编程框架 -概念模型(Akka.net或者Orleans)
    .net经典书籍
    计算机专业经典著作(转载)
    windows创建定时任务执行python脚本
    数据库中为什么不推荐使用外键约束(转载)
    《SQL Server性能调优实战》知识点汇总
    数据库索引知识汇总
    ASP.NET常见异常处理示例
    MVC的HTTP请求处理过程(IIS应用程序池、CLR线程池)
  • 原文地址:https://www.cnblogs.com/zyyhxbs/p/11678350.html
Copyright © 2011-2022 走看看