django之权限管理公共组件
在上一篇已经是学习如何搭建一个公共组件,可以拷贝到任何项目里面,实现权限的管理工作,今天再次学习下公共组件的使用
新建一个项目,并把公共组件拷贝到新项目中取,并且在setting中注册组件中间件的注册
公共组件的配置管理
在中间件中,通过导入项目的setting文件,从里面导入变量信息,所以我们在setting里面设置了如下变量信息:
# ############################## RBAC权限相关配置开始 ############################### # 无需权限控制的URLRBAC_NO_AUTH_URL = [ '/login.html', '/index.html', '/register.html', '/admin.*', '/rbac.*',]# session中保存权限信息的KeyRBAC_PERMISSION_SESSION_KEY = "rbac_permission_session_key"# Http请求中传入的参数,根据其获取GET、POST、EDIT等检测用户是否具有相应权限# 例如:# http://www.example.com?md=get 表示获取# http://www.example.com?md=post 表示添加# http://www.example.com?md=del 表示删除RBAC_QUERY_KEY = "md"RBAC_DEFAULT_QUERY_VALUE = "look"# 无权访问时,页面提示信息RBAC_PERMISSION_MSG = "无权限访问"# Session中保存菜单和权限信息的KeyRBAC_MENU_PERMISSION_SESSION_KEY = "rbac_menu_permission_session_key"RBAC_MENU_KEY = "rbac_menu_key"RBAC_MENU_PERMISSION_KEY = "rbac_menu_permission_key"# 菜单主题RBAC_THEME = "default"# ############################## RBAC权限相关配置结束 ##############################
公共组件的使用
程序如果使用的话,是需要先登陆的,RBAC_NO_AUTH_URL
这个里面设置了登陆的白名单。下面第一步先设置一个登陆页面
在
templates
下面新建一个login.html页面创建url
创建login函数
创建用户表
这个用户表 是在新的app下面创建的,这里是webapp。所以要在web这个app下面的modles里面创建这个表去,如下:
优化完成上面的login函数
上面创建完表后,我们可以在login函数里面,来验证输入的用户的正确性,通过对用户的验证,来获取当前用户的权限,菜单,已经session中的值
from django.shortcuts import render,HttpResponse,redirectfrom web import modelsdef login(request):if request.method == "GET": return render(request,'login.html')else: u = request.POST.get('username') p = request.POST.get('password') obj = models.UserInfo.objects.filter(user__username=u,user__password=p).first()#当前用户的对象这个对象里面有obj.id ,obj_nickname,obj.user_id if obj: #获取当前用户的权限 #获取当前用户的菜单 #去配置文件中获取key,写入session中 from rbac.service import initial_permission initial_permission(request,obj.user_id) #也可以自定义session request.session['user_info'] = {'username':u,'nickname':obj.nickname,'uid':obj.id} return redirect('/bgindex.html') else: return render(request,'login.html')
>上面导入了一个模块,这service.py模块中封装了权限和菜单,其中的代码如下:
#!/usr/bin/env python
-- coding:utf-8 --import re
from django.conf import settings
from . import models
def initial_permission(request, user_id):
"""
初始化权限,获取当前用户权限并添加到session中
将当前用户权限信息转换为以下格式,并将其添加到Session中
{
'/index.html': ['GET','POST','DEL','EDIT],
'/detail-(\d+).html': ['GET','POST','DEL','EDIT],
}
:param request: 请求对象:param user_id: 当前用户id:return: """"""初始化权限信息"""roles = models.Role.objects.filter(users__user_id=user_id)p2a = models.Permission2Action2Role.objects.filter(role__in=roles).values('permission__url', "action__code").distinct()user_permission_dict = {}for item in p2a: if item['permission__url'] in user_permission_dict: user_permission_dict[item['permission__url']].append(item['action__code']) else: user_permission_dict[item['permission__url']] = [item['action__code'], ]request.session[settings.RBAC_PERMISSION_SESSION_KEY] = user_permission_dict"""初始化菜单信息,将菜单信息和权限信息添加到session中"""menu_list = list(models.Menu.objects.values('id', 'caption', 'parent_id'))menu_permission_list = list(models.Permission2Action2Role.objects.filter(role__in=roles, permission__menu__isnull=False).values( 'permission_id', 'permission__url', 'permission__caption', 'permission__menu_id').distinct())request.session[settings.RBAC_MENU_PERMISSION_SESSION_KEY] = { settings.RBAC_MENU_KEY: menu_list, settings.RBAC_MENU_PERMISSION_KEY: menu_permission_list}
def fetch_permission_code(request, url):
"""
根据URL获取该URL拥有的权限,如:["GET","POST"]
:param request:
:param url:
:return:
"""
user_permission_dict = request.session.get(settings.RBAC_PERMISSION_SESSION_KEY)
if not user_permission_dict:
return []
for pattern, code_list in user_permission_dict.items():
if re.match(pattern, url):
return code_list
return []
- ** bgindex**页面搭建bgindex是后台的管理页面,这个页面是根据登陆用户的权限来显示对应的内容。这里是走中间件了,所以中间件会执行筛查的工作,中间件中的代码如下:
#!/usr/bin/env python
-- coding:utf-8 --import re
from django.conf import settings
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse
class RbacMiddleware(MiddlewareMixin):
def process_request(self, request, *args, **kwargs):
"""
检查用户是否具有权限访问当前URL
:param request:
:param args:
:param kwargs:
:return:
"""
"""跳过无需权限访问的URL""" for pattern in settings.RBAC_NO_AUTH_URL: if re.match(pattern, request.path_info): return None """获取当前用户session中的权限信息""" permission_dict = request.session.get(settings.RBAC_PERMISSION_SESSION_KEY) if not permission_dict: return HttpResponse(settings.RBAC_PERMISSION_MSG) """当前URL和session中的权限进行匹配""" flag = False for pattern, code_list in permission_dict.items(): upper_code_list = [item.upper() for item in code_list] if re.match(pattern, request.path_info): request_permission_code = request.GET.get(settings.RBAC_QUERY_KEY, settings.RBAC_DEFAULT_QUERY_VALUE).upper() if request_permission_code in upper_code_list: request.permission_code = request_permission_code request.permission_code_list = upper_code_list flag = True break if not flag: return HttpResponse(settings.RBAC_PERMISSION_MSG)
通过中间件的筛查后,我们可以得到值,然后对值进行判断来操作,如下:
上面是FBV模式,我们也可以做成CBV模式如下: dispatch是这样的工作模式:  我们自己写一个,让dispatch自己走咱们自己写的规则,多继承,会执行前面的继承,前面执行了,后面的里面的dispatch就不会执行 
报障单应用
首先在web的数据库里面创建表
from django.db import modelsfrom rbac.models import User as RbacUserimport datetimeclass UserInfo(models.Model): nickname = models.CharField(max_length=16) user = models.OneToOneField(RbacUser,on_delete=models.CASCADE) def __str__(self): return self.nicknameclass Order(models.Model): """ 保障单 """ title = models.CharField(max_length=32,verbose_name='保障标题') detail = models.TextField(verbose_name='保障详细信息') create_user = models.ForeignKey(UserInfo,related_name='aaa',on_delete=models.CASCADE) ctime = models.DateTimeField(verbose_name='创建时间') status_choice=( (1,'未处理'), (2,'处理中'), (3,'已处理') ) status = models.IntegerField(choices=status_choice,default=1) processor = models.ForeignKey(UserInfo,related_name='bbb',null=True,blank=True,on_delete=models.CASCADE) solution = models.TextField(null=True,blank=True) ptime = models.DateTimeField(null=True,blank=True) def __str__(self): return self.title
然后在setting里面注册web,
注册成功后,生成数据库表
>python3 manage.py makemigrations>python3 manage.py migrate
通过admin 来后台添加数据
数据的添加-------------------------------------------
下面是simple_tag 代码:
#!/usr/bin/env python# -*- coding:utf-8 -*-import reimport osfrom django import templatefrom django.utils.safestring import mark_safefrom django.conf import settingsregister = template.Library()def process_menu_tree_data(request): """ 根据Session中获取的菜单以及权限信息,结构化数据,生成特殊数据结构,如: [ {id:1,caption:'菜单标题',parent_id:None,status:False,opened:False,child:[...]}, ] PS: 最后一层的权限会有url,即:菜单跳转的地址 :param request: :return: """ menu_permission_dict = request.session.get(settings.RBAC_MENU_PERMISSION_SESSION_KEY) if not menu_permission_dict: raise Exception('Session中未保存当前用户菜单以及权限信息,请登录后初始化权限信息!') """ session中获取菜单和权限信息 """ all_menu_list = menu_permission_dict[settings.RBAC_MENU_KEY] menu_permission_list = menu_permission_dict[settings.RBAC_MENU_PERMISSION_KEY] all_menu_dict = {} for row in all_menu_list: row['opened'] = False row['status'] = False row['child'] = [] all_menu_dict[row['id']] = row """ 将权限信息挂靠在菜单上,并设置是否默认打开,以及默认显示 """ for per in menu_permission_list: item = {'id': per['permission_id'], 'caption': per['permission__caption'], 'url': per['permission__url'], 'parent_id': per['permission__menu_id'], 'opened': False, 'status': True} menu_id = item['parent_id'] all_menu_dict[menu_id]['child'].append(item) # 将当前URL和权限正则进行匹配,用于指示是否默认打开菜单 if re.match(item['url'], request.path_info): item['opened'] = True if item['opened']: pid = menu_id while not all_menu_dict[pid]['opened']: all_menu_dict[pid]['opened'] = True pid = all_menu_dict[pid]['parent_id'] if not pid: break if item['status']: pid = menu_id while not all_menu_dict[pid]['status']: all_menu_dict[pid]['status'] = True pid = all_menu_dict[pid]['parent_id'] if not pid: break result = [] for row in all_menu_list: pid = row['parent_id'] if pid: all_menu_dict[pid]['child'].append(row) else: result.append(row) return resultdef build_menu_tree_html(menu_list): tpl1 = """ <div class='rbac-menu-item'> <div class='rbac-menu-header'>{0}</div> <div class='rbac-menu-body {2}'>{1}</div> </div> """ tpl2 = """ <a href='{0}' class='{1}'>{2}</a> """ menu_str = "" for menu in menu_list: if not menu['status']: continue if menu.get('url'): menu_str += tpl2.format(menu['url'], "" if menu['opened'] else 'rbac-active', menu['caption']) else: if menu.get('child'): child = build_menu_tree_html(menu.get('child')) else: child = "" menu_str += tpl1.format(menu['caption'], child, "" if menu['opened'] else 'rbac-hide') return menu_str@register.simple_tagdef rbac_menu(request): """ 根据Session中当前用户的菜单信息以及当前URL生成菜单 :param request: 请求对象 :return: """ menu_tree_list = process_menu_tree_data(request) return mark_safe(build_menu_tree_html(menu_tree_list))@register.simple_tagdef rbac_css(): file_path = os.path.join('rbac', 'theme', settings.RBAC_THEME, 'rbac.css') if os.path.exists(file_path): return mark_safe(open(file_path, 'r', encoding='utf-8').read()) else: raise Exception('rbac主题CSS文件不存在')@register.simple_tagdef rbac_js(): file_path = os.path.join('rbac', 'theme', settings.RBAC_THEME, 'rbac.js') if os.path.exists(file_path): return mark_safe(open(file_path, 'r', encoding='utf-8').read()) else: raise Exception('rbac主题JavaScript文件不存在')
css 和js 通过simple_tag 应用
当点击保障单的时候,会跳转到新的保障单的页面,
但是这里要带参数url md的方法,上面代码 我们在中间件里面的默认值是GET,我们可以通过设置配置文件和中间件来修改默认值
配置文件修改:
中间件修改
当点击了保障单后,跳转到新的url,这里需要创建新的url路由。
新的页面通过模板语言,导入来实现格式
在后台给order表添加数据后,前端访问会出现数据
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。