rbac組件權限按鈕,菜單,可拔插
阿新 • • 發佈:2018-10-15
名單 elf mixin 知識 menu 查看 ict img 視圖
註意:
1、通用模板
overflow: auto; //在a和b模板中進行切換
a 模板 :左側菜單跟隨滾動條
b模板 左側以及上不動 ****
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> .header { width: 100%; heightView Code: 60px; background-color: #369; } .right { float: right; } .left { float: left; } .menu { position: absolute; top: 60px; left: 0; bottom: 0; background-color: gainsboro; width: 20%; } .content { position: absolute; top: 60px; right: 0; bottom: 0; background-color: mediumpurple; width: 80%; overflow: auto; //在a和b模板中進行切換 } </style> </head> <body> <div class="header"></div> <div class="container"> <div class="menu left"> 1111 </div> <div class="content right">222 {% block content %} {% endblock %} </div> </div> </body> </html>
2、模板繼承
users.html / roles.html 繼承自 base.html
users.html
{% extends ‘base.html‘ %} {% block con %} <h4>用戶列表</h4> {% for user in user_list %} <p>{{ user }}</p> {% endfor %} {% endblock con%}
2、權限按鈕控制:簡單控制
用戶權限不同,按鈕顯示就不同!
登錄成功後,就已經註冊了session
request.session[‘permission_list‘] = permission_list
permission_list = request.session.get(‘permission_list‘)
簡單控制: {% if "users/add" in permissions_list%}
這樣完全足夠滿足開發的需求,並且沒有BUG,但是這樣做並不嚴謹,需要更改數據表結構。
3、修改表結構
不想讓 if "/users/add/" 寫死,會有 "/roles/add/" 情況,不健壯!怎麽辦? 不應該根據表名,去判斷!!
權限不同,按鈕顯示就不同 如何做呢?
上面問題的解決辦法:
為了擴展,
# 把兩條線 合成一個線
/users/..
/roles/...
1、admin顯示字段
註意:list_display = []
2、添加action,group字段
註意點:
加了一個權限組表,
將每張表的增刪改查,劃到一個組裏面!
無論多復雜的,最終一定是對數據庫的(增刪改查)
修改表結構,重新處理中間件,登錄頁面:
目的:全是為了按鈕的粒度,同一個模板,同一個視圖,
顯示不同的數據,權限
新的數據表:
models.py
from django.db import models # Create your models here. class User(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) roles=models.ManyToManyField(to="Role") def __str__(self): return self.name class Role(models.Model): title=models.CharField(max_length=32) permissions=models.ManyToManyField(to="Permission") def __str__(self): return self.title class Permission(models.Model): title=models.CharField(max_length=32) url=models.CharField(max_length=32) action=models.CharField(max_length=32,default="") group=models.ForeignKey("PermissionGroup",default=1,on_delete=models.CASCADE) def __str__(self): return self.title class PermissionGroup(models.Model): title=models.CharField(max_length=32) def __str__(self): return self.titleView Code
4、重構數據結構
1、登錄驗證
2、構建permission_dict
3.登錄之後,重寫 initial_session(user,request)
就是:
# 在session中註冊權限列表 用戶權限
# request.session[‘permission_list‘] = permission_list
不應該是list 而是dict
# 在session中註冊權限字典
request.session[‘permission_dict‘] = permission_dict
註意點:
permission = user.roles.all().values(‘permission__url‘, ‘permission__group_id‘, ‘permission__action‘).distinct()
對數據的處理,以組為鍵
print(permissions) #把下列結構構建成一個permission_dict ‘‘‘ permissions=[ {‘permissions__url‘: ‘/users/‘, ‘permissions__group_id‘: 1, ‘permissions__action‘: ‘list‘}, {‘permissions__url‘: ‘/users/add/‘, ‘permissions__group_id‘: 1, ‘permissions__action‘: ‘add‘}, {‘permissions__url‘: ‘/roles/‘, ‘permissions__group_id‘: 2, ‘permissions__action‘: ‘list‘}, {‘permissions__url‘: ‘/users/delete/(\\d+)‘, ‘permissions__group_id‘: 1, ‘permissions__action‘: ‘delete‘}, {‘permissions__url‘: ‘users/edit/(\\d+)‘, ‘permissions__group_id‘: 1, ‘permissions__action‘: ‘edit‘} ] ‘‘‘View Code
{1: {‘urls‘: [‘/users/‘, ‘/users/add/‘, ‘/users/delete/(\\d+)/‘, ‘/users/edit/(\\d+)/‘], ‘actions‘: [‘list‘, ‘add‘, ‘delete‘, ‘edit‘]}, 2: {‘urls‘: [‘/roles/‘], ‘actions‘: [‘list‘]}}
def initial_session(user,request): #方案一 # permissions = user.roles.all().values("permissions__url").distinct() # print(permissions) # permission_list = [] # for item in permissions: # print("items",item) # permission_list.append(item["permissions__url"]) # print(permission_list) # request.session["permission_list"] = permission_list #方案二 permissions = user.roles.all().values("permissions__url","permissions__group_id","permissions__action").distinct() print(permissions) permission_dict = {} temp = [] for item in permissions: gid = item.get(‘permissions__group_id‘) if not gid in permission_dict: permission_dict[gid] = { "urls": [item["permissions__url"], ], "actions": [item["permissions__action"], ] } else: permission_dict[gid]["urls"].append(item["permissions__url"]) permission_dict[gid]["actions"].append(item["permissions__action"]) print(permission_dict) request.session["permission_dict"]=permission_dict #註冊菜單權限 permissions = user.roles.all().values("permissions__url", "permissions__group__title", "permissions__action").distinct() menu_permission_list=[] for item in permissions: if item["permissions__action"] == "list": menu_permission_list.append((item["permissions__url"],item["permissions__group__title"])) # print("permission",men_permission_list) #註冊到session中 request.session["menu_permission_list"]=menu_permission_list
5、限制權限粒度
1、中間件校驗權限:
# 註意:妙 !!
request.actions = item["actions"]
rbac.py方案二
import re from django.utils.deprecation import MiddlewareMixin from django.shortcuts import HttpResponse,redirect class ValidPermission(MiddlewareMixin): def process_request(self,request): # 當前訪問路徑 current_path = request.path_info # 檢查是否屬於白名單 valid_url_list=["/login/","/reg/","/admin/.*"] for valid_url in valid_url_list: ret=re.match(valid_url,current_path) if ret: return None # 校驗是否登錄 user_id=request.session.get("user_id") if not user_id: return redirect("/login/") #校驗權限2 permission_dict=request.session.get("permission_dict",[])#加個列表防止空不可循環導致保存 for item in permission_dict.values(): urls=item[‘urls‘] for reg in urls: reg="^%s$"%reg ret = re.match(reg,current_path) if ret: print("actions",item["actions"]) request.actions = item["actions"] return None return HttpResponse("沒有訪問權限!")
#在中間件校驗權限的過程中,匹配到哪兒成功了,把匹配到那裏對應的actions取出來,放到request.actions中.
模板層,權限按鈕控制
2用類來實現
from django.shortcuts import render, HttpResponse # Create your views here. from rbac.models import * from rbac.service.perssions import * class Per(object): def __init__(self, actions): self.actions = actions def add(self): return "add" in self.actions def delete(self): return "delete" in self.actions def edit(self): return "edit" in self.actions def list(self): return "list" in self.actions def users(request): user_list = User.objects.all() permission_list = request.session.get("permission_list") # 查詢當前登錄人的名字 id = request.session.get("user_id") user = User.objects.filter(id=id).first() print(user) per = Per(request.actions) return render(request, "users.html", locals()) def add_user(request): return HttpResponse(‘add user‘) def delete_user(request, id): return HttpResponse(‘delete_user‘) def edit_user(request, id): return HttpResponse(‘edit_user‘) def roles(request): role_list = Role.objects.all() per = Per(request.actions) print(request.actions) return render(request, "roles.html", locals()) def login(request): if request.method == "POST": user = request.POST.get("user") pwd = request.POST.get("pwd") user = User.objects.filter(name=user, pwd=pwd).first() if user: ############## 在session中註冊用戶 request.session[‘user_id‘] = user.pk ############# 在session中註冊權限list initial_session(request, user) return HttpResponse("登錄成功") return render(request, ‘login.html‘, locals())View
3、效果
不同的用戶,具有不同的權限,權限不同,顯示的按鈕就不同
6、權限不同,菜單顯示不同
只有查看,有必要放到菜單欄!
即:action == list 放到 菜單欄中
1.用戶登錄後,在initial_session中,註冊菜單權限
註意:permission__group__title 還可以這樣用,跨了3張表!!
2、menu
可以實現,菜單顯示!但是不行,為什麽?
因為模板繼承,只繼承樣式,不繼承數據!所有需要用到 自定義標簽(inclusion_tag)
3、自定義標簽(inclusion_tag)
my_tags.py
# Author:Jesi # Time : 2018/9/17 13:44 from django import template register=template.Library() @register.inclusion_tag("rbac/menu.html") def get_menu(request,): menu_permission_list=request.session["menu_permission_list"] return {"menu_permission_list":menu_permission_list}
+
7、可拔插配置:包...建在哪個App
屬於權限的就建在rbac的APP裏,因為rpac最後是可插拔的組件!!
users.html / roles.html / base.html / menu.html
是和權限相關的,所以應該放在 rbac/templates/... 方便以後copy走!!
djangod的render去渲染 .html 時,先到項目的 templates 下找,找不到,再到App下 templates 下找,
最後找不到,才報錯!!
如果多個App的templates 下的.html重名怎麽辦? django 會根據註冊的順序顯示!
解決辦法:
項目/rbac/templates/rbac/xxx.html
這時調用:
return render(request, ‘rbac/users.html‘, locals())
註意:
templates 或者 templatetag 註意多個app下面 的文件名 有可能都會重名!!
辦法:就是 eg:/rbac/templates/rbac/xxx.html 或者不起重名
註意:
如果 base.html 在項目下有,在App下有,先找項目下的,找不到才找App
全局可以覆蓋局部的!!
臨時補充問題(與rbac無關):
路徑自動添加
知識點:路徑自動添加問題:
http://127.0.0.1:8010/users
http://127.0.0.1:8010/users/
瀏覽器發請求:
django 發現之後,發了一個重定向的 url 加了一個 /
所有才能匹配上:
path(‘users/‘, views.users),
如何讓django不給瀏覽器發重定向,不加 /
配置:
APPEND_SLASH = False
APPEND_SLASH = True # 默認為 True
ajax 也是,django會默認的加 / 發重定向
1、django瀏覽器重定向
2、APPEND_SLASH = False
ajax 也是,django會默認的加 / 發重定向
rbac組件權限按鈕,菜單,可拔插