您好,登錄后才能下訂單哦!
在上一篇已經是學習如何搭建一個公共組件,可以拷貝到任何項目里面,實現權限的管理工作,今天再次學習下公共組件的使用
在中間件中,通過導入項目的setting文件,從里面導入變量信息,所以我們在setting里面設置了如下變量信息:
# ############################## RBAC權限相關配置開始 ##############################
# # 無需權限控制的URL
RBAC_NO_AUTH_URL = [
'/login.html',
'/index.html',
'/register.html',
'/admin.*',
'/rbac.*',
]
# session中保存權限信息的Key
RBAC_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中保存菜單和權限信息的Key
RBAC_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頁面
from django.shortcuts import render,HttpResponse,redirect
from web import models
def 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
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
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是這樣的工作模式:
![](https://s1.51cto.com/images/blog/201805/17/d3b613c271249192498f222e6980b84f.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
我們自己寫一個,讓dispatch自己走咱們自己寫的規則,多繼承,會執行前面的繼承,前面執行了,后面的里面的dispatch就不會執行
![](https://s1.51cto.com/images/blog/201805/17/1c5ddfdb763e7cbd45c710aa2248f5a8.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
![](https://s1.51cto.com/images/blog/201805/17/d429cda4c38f86fb3276e2ec04b266ed.png?x-oss-process=image/watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=)
首先在web的數據庫里面創建表
from django.db import models
from rbac.models import User as RbacUser
import datetime
class UserInfo(models.Model):
nickname = models.CharField(max_length=16)
user = models.OneToOneField(RbacUser,on_delete=models.CASCADE)
def __str__(self):
return self.nickname
class 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 re
import os
from django import template
from django.utils.safestring import mark_safe
from django.conf import settings
register = 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 result
def 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_tag
def 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_tag
def 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_tag
def 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文件不存在')
當點擊保障單的時候,會跳轉到新的保障單的頁面,
但是這里要帶參數url md的方法,上面代碼 我們在中間件里面的默認值是GET,我們可以通過設置配置文件和中間件來修改默認值
配置文件修改:
中間件修改
當點擊了保障單后,跳轉到新的url,這里需要創建新的url路由。
新的頁面通過模板語言,導入來實現格式
在后臺給order表添加數據后,前端訪問會出現數據
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。