效果圖:
一、models層給權限增加url的別名
這是做是為了在模板用別名判斷當前用戶是否有這個url(權限)
rbac/models.py
class Permission(models.Model): """ 權限表 """ title = models.CharField(verbose_name='標題', max_length=32) url = models.CharField(verbose_name='含正則的URL', max_length=128) menu = models.ForeignKey(verbose_name='所屬菜單', to=Menu, null=True, blank=True, help_text='null表示不是菜單,非null表示是二級菜單', on_delete=models.CASCADE ) name = models.CharField(verbose_name='url的別名', max_length=32, unique=True) # + pid = models.ForeignKey(verbose_name='關聯的權限', to='Permission', null=True, blank=True, related_name='parents', help_text='對於非菜單權限需要選擇一個可以成為菜單的權限,用於做默認展開和選中菜單', on_delete=models.CASCADE ) def __str__(self): return self.title
注意:剛創建的時候設置成null=True和blank=True,當添加完數據后再設置unique=True,並刪除null=True和blank=True
二、在初始化權限中增加別名
把用戶權限以字典的形式儲存,別名作為key。values還是一個字典,儲存其他信息。
rbac/service/init_permission.py
from permission_learn import settings def init_permission(current_user, request): """ 用戶權限的初始化 :param current_user: 當前登錄用戶 :param request: :return: """ permission_menu_queryset = current_user.roles.filter(permissions__isnull=False).values( 'permissions__id', 'permissions__title', 'permissions__url', 'permissions__name', 'permissions__pid_id', 'permissions__pid__title', # + 'permissions__pid__url', 'permissions__menu_id', 'permissions__menu__title', 'permissions__menu__icon', ) permission_dict = {} # + menu_dict = {} for item in permission_menu_queryset: permission_dict[item['permissions__name']] = { 'id': item['permissions__id'], 'title': item['permissions__title'], 'url': item['permissions__url'], 'pid': item['permissions__pid_id'], 'p_title': item['permissions__pid__title'], 'p_url': item['permissions__pid__url'], } menu_id = item['permissions__menu_id'] if not menu_id: continue second_menu = {'id': item["permissions__id"], 'title': item['permissions__title'], 'url': item['permissions__url']} if menu_id in menu_dict: menu_dict[menu_id]['second_menu'].append(second_menu) else: menu_dict[menu_id] = { 'title': item['permissions__menu__title'], 'icon': item['permissions__menu__icon'], 'second_menu': [second_menu, ] } request.session[settings.PERMISSION_SESSION_KEY] = permission_dict request.session[settings.MENU_SESSION_KEY] = menu_dict
三、中間件處理
rbac/middlewares/rbac.py
沒有太大變化,換一下名字就行
import re from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse from permission_learn import settings class RbacMiddleware(MiddlewareMixin): def process_request(self, request): white_list = settings.WHITE_LIST current_path = request.path for valid_url in white_list: if re.match(valid_url, current_path): return None permission_dict = request.session.get(settings.PERMISSION_SESSION_KEY) if not permission_dict: return HttpResponse('請先登錄 ') has_permission = False url_record = [ {'title': '首頁', 'url': '#'} ] for item in permission_dict.values(): regex = '^%s$' % item['url'] if re.match(regex, current_path): has_permission = True request.current_selected_permission = item['pid'] or item['id'] if not item['pid']: # 選中的是二級菜單 url_record.extend([ {'title': item['title'], 'url': item['url'], 'class': 'active'} ]) else: # 選中的是具體權限 url_record.extend([ {'title': item['p_title'], 'url': item['p_url']}, {'title': item['title'], 'url': item['url'], 'class': 'active'}, ]) request.breadcrumb = url_record # 通過request,把儲存信息傳給用戶 break if not has_permission: return HttpResponse('未獲取權限,請先獲取權限')
四、模板處理
在templatestag里判斷用戶是否有權限(是否有url的別名)
rbac/templatestag/rbac.py
@register.filter() def has_permission(request, name): """判斷是否有權限""" if name in request.session[settings.PERMISSION_SESSION_KEY]: return True
在需要把權限控制到按鈕的模板傳入request,和url的別名,並進行判斷。這里拿用戶列表舉例
業務app/templates/customer_list.html
{% extends 'layout.html' %} {% load rbac %} <!-- 系統會默認找到templatetags的文件下面的rbac模塊 --> ... {% if request|has_permission:'customer_add' %} <a class="btn btn-default" href="/customer/add/"> <i class="fa fa-plus-square" aria-hidden="true"></i> 添加客戶 </a> {% endif %} {% if request|has_permission:'customer_import' %} <a class="btn btn-default" href="/customer/import/"> <i class="fa fa-file-excel-o" aria-hidden="true"></i> 批量導入 </a> {% endif %} {% if request|has_permission:'customer_edit' or request|has_permission:'customer_del' %} <th>選項</th> {% endif %} {% if request|has_permission:'customer_edit' or request|has_permission:'customer_del' %} <td> {% if request|has_permission:'customer_edit' %} <a style="color: #333333;" href="/customer/edit/{{ row.id }}/"> <i class="fa fa-edit" aria-hidden="true"></i> </a> {% endif %} {% if request|has_permission:'customer_del' %} | <a style="color: #d9534f;" href="/customer/del/{{ row.id }}/"> <i class="fa fa-trash-o"></i> </a> {% endif %} </td> {% endif %} ...