权限管理——版本2
1.完成目标
菜单相关: [ {‘menu_id‘:1,‘menu_title‘:‘菜单1‘,‘title‘:‘用户列表‘,‘url‘:‘/userinfo/‘}, {‘menu_id‘:1,‘menu_title‘:‘菜单1‘,‘title‘:‘订单列表‘,‘url‘:‘/order/‘}, {‘menu_id‘:2,‘menu_title‘:‘菜单2‘,‘title‘:‘xxx列表‘,‘url‘:‘/xxx/‘}, {‘menu_id‘:3,‘menu_title‘:‘菜单2‘,‘title‘:‘aaa列表‘,‘url‘:‘/aaa/‘}, ] 菜单1 用户管理 菜单2 订单管理 分级,默认展开选中。 构建数据结构: { 1: { ‘menu_id‘: 1, ‘menu_title‘: ‘菜单一‘, ‘active‘: None, ‘children‘: [ {‘title‘: ‘订单列表‘, ‘url‘: ‘/order/‘, ‘active‘: None} ] } 2: { ‘menu_id‘: 2, ‘menu_title‘: ‘菜单二‘, ‘active‘: True, ‘children‘: [ {‘title‘: ‘用户列表‘, ‘url‘: ‘/userinfo/‘, ‘active‘: True} ] }, } 小结: 菜单相关的数据结构,还需要和当前请求的url匹配,匹配成功,actice为True。 active有两个操作: 1.目标是否变红 2.目标是否展开或缩小。
5.从构建数据结构传过来的数据格式变了: 做了一个settings配置名,改以下就不需要每个地方都改。
6.循环数据,拿字典里面的key,value,字典套字典,要学会取值。
7.为了让视图知道codes,我们还需要取codes。
8.把生成菜单的标签放到simple_tag里load就可以了
9.扩展一个inclusion_tag自定义页面的功能,后面只需要跟一个页面。
结果实例图:
2.代码
1.app01/views.py
from django.shortcuts import render,redirect,HttpResponse from rbac import models from rbac.service.init_permission import init_permission from django.conf import settings import re def login(reqeust): if reqeust.method == ‘GET‘: return render(reqeust,‘login.html‘) else: user = reqeust.POST.get(‘user‘) pwd = reqeust.POST.get(‘pwd‘) print(reqeust.POST) user = models.User.objects.filter(username=user,password=pwd).first() print(user) if not user: return render(reqeust,‘login.html‘) init_permission(user,reqeust) print(111) return redirect(‘/index/‘) def index(request): print(222) return HttpResponse(‘欢迎登录 哈哈哈‘) class BasePagePermission(object): def __init__(self,code_list): self.code_list = code_list def has_add(self): if ‘add‘ in self.code_list: return True def has_edit(self): if ‘edit‘ in self.code_list: return True def has_del(self): if ‘del‘ in self.code_list: return True def userinfo(request): print(request.permisstion_code_list) page_permission = BasePagePermission(request.permisstion_code_list) data_list = [ {‘id‘:1,‘name‘:‘xxx1‘}, {‘id‘:2,‘name‘:‘xxx2‘}, {‘id‘:3,‘name‘:‘xxx3‘}, {‘id‘:4,‘name‘:‘xxx4‘}, {‘id‘:5,‘name‘:‘xxx5‘}, ] menu_list = request.session[settings.PERMISSTION_MENU_KEY] return render(request,‘userinfo.html‘,{‘data_list‘:data_list,‘page_permission‘:page_permission}) def userinfo_add(request): page_permission = BasePagePermission(request.permisstion_code_list) return HttpResponse(‘添加用户页面‘) class OrderPagePermission(BasePagePermission): def has_report(self): if ‘report‘ in self.code_list: return True def order(request): order_permission = OrderPagePermission(request.permisstion_code_list) return render(request, ‘order.html‘)
2.settings:
STATIC_URL = ‘/static/‘ PERMISSTION_URL_DICT = ‘permissions_url_dict‘ PERMISSTION_MENU_KEY = ‘asdasdasdada‘ VALID_URL = [ ‘/login/‘, ‘/admin.*/‘ ]
3.urls.py
from django.conf.urls import url from django.contrib import admin from rbac import views from app01 import views as app01_views urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^test/‘,views.test), url(r‘^login/‘,app01_views.login), url(r‘^index/‘,app01_views.index), url(r‘^userinfo/$‘,app01_views.userinfo), url(r‘^userinfo/add$‘,app01_views.userinfo_add), url(r‘^order/$‘,app01_views.order) ]
4.rbac/middlewares/rbac.py
import re from permission import settings from django.shortcuts import redirect,HttpResponse class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, ‘process_request‘): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, ‘process_response‘): response = self.process_response(request, response) return response class RbacMiddleware(MiddlewareMixin): def process_request(self,request): ‘‘‘ 1.获取当前请求的url: 使用 request.path_info 2.获取session中的保存的用户权限: 使用request.session.get().不能request.session[],因为可能没数据。 3.设置白名单,获取到白名单的放行数据,和用户所拥有的权限url,匹配。 如果匹配,就不需要经过权限的检查。 4.当用户访问了组的列表页面后,就应该知道他在这个组里还有什么权限。 -1.分组: 1可以是用户组, 2是订单组 -2.不当是用户列表页面需要知道他的所有权限,其它页面也应该知道。使用codes来获取。 -3. 以上这样设置,不管什么页面都能知道所有的权限url,找到codes就可以。 list = { 1:{ ‘codes‘:[‘list‘,‘add‘,‘edit‘,‘del‘] ‘urls‘:[ /userinfo/ /userinfo/add/ /userinfo/edit/(\d+)/ /userinfo/del/(\d+)/ ] } } 5.从构建数据结构传过来的数据格式变了: 做了一个settings配置名,改以下就不需要每个地方都改。 6.循环数据,拿字典里面的key,value,字典套字典,要学会取值。 7.为了让视图知道codes,我们还需要取codes。 8.把生成菜单的标签放到simple_tag里load就可以了 9.扩展一个inclusion_tag自定义页面的后面只需要跟一个页面。 ‘‘‘ current_url = request.path_info for url in settings.VALID_URL: if re.match(url,current_url): print(url,current_url) return None permission_dict = request.session.get(settings.PERMISSTION_URL_DICT) # 拿到url格式的数据 if not permission_dict: return redirect(‘/login/‘) flag = False for group_id,code_url in permission_dict.items(): # 用in不行,含正则的url使用in会匹配不了,所要要用正则:re.match for db_url in code_url[‘urls‘]: regax = ‘^{0}$‘.format(db_url) #加上起止符,绝对匹配。 if re.match(regax, current_url): # 如果匹配成功,就已等 request.permisstion_code_list = code_url[‘codes‘] #取到codes列表,存到request里 flag = True break if flag: break if not flag: return HttpResponse(‘无权访问‘)
5.rbac/service/init_permission.py
from django.conf import settings def init_permission(user,request): ‘‘‘ 初始化权限信息,把权限url放到session。 :param user: :param request: :return: list = { 1:{ ‘codes‘:[‘list‘,‘add‘,‘edit‘,‘del‘] ‘urls‘:[ /userinfo/ /userinfo/add/ /userinfo/edit/(\d+)/ /userinfo/del/(\d+)/ ] } } 菜单相关: [ {‘menu_id‘:1,‘menu_title‘:‘菜单1‘,‘title‘:‘用户列表‘,‘url‘:‘/userinfo/‘}, {‘menu_id‘:1,‘menu_title‘:‘菜单1‘,‘title‘:‘订单列表‘,‘url‘:‘/order/‘}, {‘menu_id‘:2,‘menu_title‘:‘菜单2‘,‘title‘:‘xxx列表‘,‘url‘:‘/xxx/‘}, {‘menu_id‘:3,‘menu_title‘:‘菜单2‘,‘title‘:‘aaa列表‘,‘url‘:‘/aaa/‘}, ] 菜单1 用户管理 菜单2 订单管理 分级,默认展开选中。 构建数据结构: { 1: { ‘menu_id‘: 1, ‘menu_title‘: ‘菜单一‘, ‘active‘: None, ‘children‘: [ {‘title‘: ‘订单列表‘, ‘url‘: ‘/order/‘, ‘active‘: None} ] } 2: { ‘menu_id‘: 2, ‘menu_title‘: ‘菜单二‘, ‘active‘: True, ‘children‘: [ {‘title‘: ‘用户列表‘, ‘url‘: ‘/userinfo/‘, ‘active‘: True} ] }, } 小结: 菜单相关的数据结构,还需要和当前请求的url匹配,匹配成功,actice为True。 active有两个操作: 1.目标是否变红 2.目标是否展开或缩小。 ‘‘‘ permission_list2 = user.roles.values(‘permissions__title‘, #权限名称 ‘permissions__url‘, #权限url ‘permissions__is_menu‘, #权限是否是菜单 ‘permissions__codes‘, #权限的codes ‘permissions__group_id‘, #组id ‘permissions__group__menu_id‘, #菜单id ‘permissions__group__menu__title‘ #菜单名称 ).distinct() menu_list = [] #去掉不是菜单的url for item in permission_list2: if not item[‘permissions__is_menu‘]: continue tpl = { ‘menu_id‘:item[‘permissions__group__menu_id‘], ‘menu_title‘:item[‘permissions__group__menu__title‘], ‘title‘:item[‘permissions__title‘], ‘url‘:item[‘permissions__url‘], ‘active‘:False } menu_list.append(tpl) request.session[settings.PERMISSTION_MENU_KEY] = menu_list #权限相关 result = {} for item in permission_list2: group_id = item[‘permissions__group_id‘] code = item[‘permissions__codes‘] url = item[‘permissions__url‘] if group_id in result: result[group_id][‘codes‘].append(code) result[group_id][‘urls‘].append(url) else: result[group_id] = { ‘codes‘:[code,], ‘urls‘:[url,], } request.session[settings.PERMISSTION_URL_DICT] = result #拿到用户请求url,和session做对比,如果在,可访问,不在,一边去。
6.rbac/static/rabc/rbac.css
.item-permission{ padding: 3px 10px; } .item-permission a{ display: block; } .item-permission a.active{ color: red; } .hide{ display: none; }
7..rbac/static/rabc/rbac.js
/** * Created by Administrator on 2017/11/8. */ $(function () { $(‘.item-title‘).click(function () { if($(this).next().hasClass(‘hide‘)){ $(this).next().removeClass(‘hide‘) }else{ $(this).next().addClass(‘hide‘) } }) });
8.rbac/templatetags/rbac.py
import re from django.template import Library from django.conf import settings register = Library() @register.inclusion_tag(‘xxxxx.html‘) def menu_html(request): ‘‘‘ 去session中获取菜单相关信息,匹配当前url,生成菜单。 :param request: :return: ‘‘‘ menu_list = request.session[settings.PERMISSTION_MENU_KEY] current_url = request.path_info result = {} for item in menu_list: url = item[‘url‘] print(url) regex = ‘^{0}$‘.format(url) active = False if re.match(regex,current_url): active = True menu_id = item[‘menu_id‘] if menu_id in result: result[menu_id][‘children‘].append({‘title‘:item[‘title‘],‘url‘:item[‘url‘],‘active‘:active}) if active: result[menu_id][‘active‘] = True else: result[menu_id] = { ‘menu_id‘:menu_id, ‘menu_title‘:item[‘menu_title‘], ‘active‘: active, ‘children‘: [ {‘title‘: item[‘title‘], ‘url‘: item[‘url‘], ‘active‘: active}, ] } return {‘menu_dict‘:result}
9.xxxxx.html
{% for k,item in menu_dict.items %} <div class="item"> <div class="item-title">{{ item.menu_title }}</div> {% if item.active %} <div class="item-permission"> {% else %} <div class="item-permission hide"> {% endif %} {% for v in item.children %} {% if v.active %} <a href="{{ v.url }}" class="active">{{ v.title }}</a> {% else %} <a href="{{ v.url }}">{{ v.title }}</a> {% endif %} {% endfor %} </div> </div> {% endfor %}