一, 引入
1.为什么要有权限?
2.为什么要开发权限的组件?
3.在web开发中,什么是权限?
4.表结构的设计
权限表
ID |
URL |
1 |
/user_list/ |
2 |
/customer_list/ |
用户表
ID |
USER_NAME |
1 |
root |
2 |
root 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 = 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('没有访问权限,请联系管理员') |
| |
| |
| WHITE_LIST = [ |
| r'^/admin/', |
| r'^/login/$', |
| r'^/register/$', |
| ] |
| |
| |
| 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 = 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 = 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> |
| |
| @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 = 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 |
| |
| |
| |
| { |
| 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 |
| |
| 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(): |
| |
| 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 = 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(): |
| |
| 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') |
| @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)) |
| |
| 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() |
| |
| router_dict = get_all_url_dict(ignore_namespace_list=['admin']) |
| |
| |
| permissions_name_set = set([i.name for i in permissions]) |
| |
| 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() |
| |
| user_has_roles = models.UserInfo.objects.filter(id=uid).values('id', 'roles') |
| |
| |
| 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') |
| menu_dict = {} |
| |
| for item in queryset: |
| |
| 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: |
| |
| 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: |
| |
| 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 |
| } |
| ) |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了