權限管理
創建一個rbac和app的應用,這個rbac主要是用來存放權限的,全稱叫做基於角色權限控制
一、先看配置文件合適不,給創建的rbac在配置文件里面設置一下
找到INSTALLED_APPS=【'rbac'】
二、設計表結構
models中創建類:五個類,七張表
角色表:
用戶表:
權限表:
組表:
菜單表:
角色表和權限表是多對多的關系(一個角色可以有多個權限,一個權限可以對應多個角色)
用戶表和角色表是多對多的關系(一個用戶可以有多個角色,一個角色有多個用戶)
所以有會多生成兩張關系表
一個菜單下面有多個組
一個組下面有多個菜單
一個菜單下面有多個權限
from django.db import models# Create your models here.
class Role(models.Model):
'''
角色表
'''
title = models.CharField(max_length=32,verbose_name="角色名")
permissions = models.ManyToManyField(to="Permission",verbose_name="具有的所有權限", blank=True) # 建立用戶表和角色表的多對多關系<span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self): </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> self.title </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta: verbose_name_plural </span>= <span style="color: #800000;">"</span><span style="color: #800000;">角色表</span><span style="color: #800000;">"</span>
class Group(models.Model):
caption = models.CharField(max_length=32,verbose_name="組名稱")
menu = models.ForeignKey(to="Menu",verbose_name="所屬菜單",default=1,related_name="menu")
class Menu(models.Model):
title = models.CharField(max_length=32)class Permission(models.Model):
'''
權限表
'''
title = models.CharField(max_length=32,verbose_name="標題")
url = models.CharField(max_length=64,verbose_name="帶正則的URL")
# is_mune = models.BooleanField(verbose_name="是否是菜單",default=0)
menu_gp = models.ForeignKey(verbose_name="組內菜單",to="Permission",blank=True,null=True) #自關聯
#主頁就可以設置為菜單,當點擊菜單的時候才可以做具體的操作
codes = models.CharField(max_length=32,verbose_name="代碼",default=1)
group = models.ForeignKey(to="Group",verbose_name="所屬組",null=True) #新添加的字段記得設置默認值<span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self): </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> self.title </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta: </span><span style="color: #800000;">'''</span><span style="color: #800000;">中文顯示</span><span style="color: #800000;">'''</span><span style="color: #000000;"> verbose_name_plural </span>= <span style="color: #800000;">"</span><span style="color: #800000;">權限表</span><span style="color: #800000;">"</span>
class UserInfo(models.Model):
'''
用戶表
'''
username = models.CharField(max_length=32,verbose_name="用戶名")
password = models.CharField(max_length=64,verbose_name="密碼")
email = models.CharField(max_length=32,verbose_name="郵箱")
roles = models.ManyToManyField(to="Role",verbose_name="具有的所有角色",blank=True) #建立用戶和角色的多對多關系<span style="color: #0000ff;">def</span> <span style="color: #800080;">__str__</span><span style="color: #000000;">(self): </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> self.username </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Meta: verbose_name_plural </span>= <span style="color: #800000;">"</span><span style="color: #800000;">用戶表</span><span style="color: #800000;">"</span></pre>
三、通過django admin錄入權限數據
- 先創建一個超級用戶
- 用戶名 root
- 密碼 zhy123456
- 在admin.py 中
from rbac import models
admin.site.register(models.Permission)
admin.site.register(models.Role)
admin.site.register(models.UserInfo)
這樣的話上去的是英文的,如果你想讓中文顯示就在類中加一個類
class Meta:
verbose_name_plural = "權限表"
- 當你給關聯字段錄入數據的時候會有錯誤提示,那么在類中你的那個關聯字段在加一個屬性blank = True 可以為空
permissions = models.ManyToManyField(to="Permission",verbose_name="具有的所有權限", blank=True)
四、編寫登錄
用戶登錄后:
獲取當前用戶具有的所有角色
獲取當前用戶具有的所有權限(並且去重)
#獲取當前的用戶對象 user = models.UserInfo.objects.filter(username=name,password=password).first() #獲取當前用戶的所有角色user.roles.all() #獲取當前用戶的所有權限 permission_list = user.roles.all().values("permissions__title","permissions__url","permissions__is_mune").distinct() print(permission_list)
登錄成功之后初始化---把所有的url都拿出來並且保存到session里
1、可以建一個server的包,在里面建一個初始化的init_perssion.py文件
2、定義函數
#!usr/bin/env python # -*- coding:utf-8 -*- from rbac import models from day7權限管理 import settings def init_permission(user,request): #獲取當前的用戶對象 ''' 獲取所有權限中的url並放在session中 :param user: :param request: :return: '''<span style="color: #008000;">#</span><span style="color: #008000;">user.roles.all()獲取當前用戶的所有角色</span> <span style="color: #008000;">#</span><span style="color: #008000;">獲取當前用戶的所有權限</span> permission_list =<span style="color: #000000;"> user.roles.all().values( </span><span style="color: #800000;">"</span><span style="color: #800000;">permissions__id</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800000;">"</span><span style="color: #800000;">permissions__title</span><span style="color: #800000;">"</span>, <span style="color: #008000;">#</span><span style="color: #008000;">用戶列表</span> <span style="color: #800000;">"</span><span style="color: #800000;">permissions__url</span><span style="color: #800000;">"</span>, <span style="color: #008000;">#</span><span style="color: #008000;">url</span> <span style="color: #800000;">"</span><span style="color: #800000;">permissions__menu_gp</span><span style="color: #800000;">"</span>, <span style="color: #008000;">#</span><span style="color: #008000;">組內菜單id,如果為null表示是菜單</span> <span style="color: #800000;">"</span><span style="color: #800000;">permissions__codes</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800000;">"</span><span style="color: #800000;">permissions__group_id</span><span style="color: #800000;">"</span><span style="color: #000000;">, </span><span style="color: #800000;">"</span><span style="color: #800000;">permissions__group__menu__title</span><span style="color: #800000;">"</span>, <span style="color: #008000;">#</span><span style="color: #008000;">菜單名稱</span> <span style="color: #800000;">"</span><span style="color: #800000;">permissions__group__menu__id</span><span style="color: #800000;">"</span> <span style="color: #008000;">#</span><span style="color: #008000;">菜單id</span>
).distinct()
</span><span style="color: #0000ff;">print</span>(<span style="color: #800000;">"</span><span style="color: #800000;">-----------------</span><span style="color: #800000;">"</span><span style="color: #000000;">,permission_list) </span><span style="color: #008000;">#</span><span style="color: #008000;">菜單相關</span> sub_permisson_list =<span style="color: #000000;"> [] </span><span style="color: #0000ff;">for</span> item <span style="color: #0000ff;">in</span><span style="color: #000000;"> permission_list: tpl </span>=<span style="color: #000000;"> { </span><span style="color: #800000;">"</span><span style="color: #800000;">id</span><span style="color: #800000;">"</span>:item[<span style="color: #800000;">"</span><span style="color: #800000;">permissions__id</span><span style="color: #800000;">"</span><span style="color: #000000;">], </span><span style="color: #800000;">"</span><span style="color: #800000;">title</span><span style="color: #800000;">"</span>:item[<span style="color: #800000;">"</span><span style="color: #800000;">permissions__title</span><span style="color: #800000;">"</span><span style="color: #000000;">], </span><span style="color: #800000;">"</span><span style="color: #800000;">url</span><span style="color: #800000;">"</span>:item[<span style="color: #800000;">"</span><span style="color: #800000;">permissions__url</span><span style="color: #800000;">"</span><span style="color: #000000;">], </span><span style="color: #800000;">"</span><span style="color: #800000;">menu_group_id</span><span style="color: #800000;">"</span>:item[<span style="color: #800000;">"</span><span style="color: #800000;">permissions__group_id</span><span style="color: #800000;">"</span><span style="color: #000000;">], </span><span style="color: #800000;">"</span><span style="color: #800000;">menu_id</span><span style="color: #800000;">"</span>:item[<span style="color: #800000;">"</span><span style="color: #800000;">permissions__group__menu__id</span><span style="color: #800000;">"</span><span style="color: #000000;">], </span><span style="color: #800000;">"</span><span style="color: #800000;">menu_title</span><span style="color: #800000;">"</span>:item[<span style="color: #800000;">"</span><span style="color: #800000;">permissions__group__menu__title</span><span style="color: #800000;">"</span><span style="color: #000000;">] } sub_permisson_list.append(tpl) request.session[settings.PERMISSION_MENU_KEY] </span>=<span style="color: #000000;"> sub_permisson_list </span><span style="color: #008000;">#</span><span style="color: #008000;"> 1、去掉不是菜單的url</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 菜單操作</span> <span style="color: #008000;">#</span><span style="color: #008000;"> menu_list = []</span> <span style="color: #008000;">#</span><span style="color: #008000;"> for item in permission_list:</span> <span style="color: #008000;">#</span><span style="color: #008000;"> if not item["permissions__is_mune"]: # 如果不是菜單就繼續</span> <span style="color: #008000;">#</span><span style="color: #008000;"> continue</span> <span style="color: #008000;">#</span><span style="color: #008000;"> else: # 否則是菜單的話就把菜單添加到列表里面</span> <span style="color: #008000;">#</span><span style="color: #008000;"> tpl = {</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "menu_id": item["permissions__group__menu__id"],</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "menu_title": item["permissions__group__menu__title"],</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "title": item["permissions__title"],</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "url": item["permissions__url"],</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "active": False</span> <span style="color: #008000;">#</span><span style="color: #008000;"> }</span> <span style="color: #008000;">#</span><span style="color: #008000;"> menu_list.append(tpl)</span> <span style="color: #008000;">#</span><span style="color: #008000;"> request.session[settings.PERMISSION_MENU_KEY] = menu_list #吧所有的菜單都放在session里面</span> <span style="color: #008000;">#</span><span style="color: #008000;"> print("xcvxvxv", menu_list)</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 權限相關</span> result =<span style="color: #000000;"> {} </span><span style="color: #0000ff;">for</span> item <span style="color: #0000ff;">in</span><span style="color: #000000;"> permission_list: group_id </span>= item[<span style="color: #800000;">"</span><span style="color: #800000;">permissions__group_id</span><span style="color: #800000;">"</span><span style="color: #000000;">] url </span>=item[<span style="color: #800000;">"</span><span style="color: #800000;">permissions__url</span><span style="color: #800000;">"</span><span style="color: #000000;">] code </span>= item[<span style="color: #800000;">"</span><span style="color: #800000;">permissions__codes</span><span style="color: #800000;">"</span><span style="color: #000000;">] </span><span style="color: #0000ff;">if</span> group_id <span style="color: #0000ff;">in</span><span style="color: #000000;"> result: </span><span style="color: #008000;">#</span><span style="color: #008000;">如果在說明url和code已經生成了</span> result[group_id][<span style="color: #800000;">"</span><span style="color: #800000;">codes</span><span style="color: #800000;">"</span><span style="color: #000000;">].append(code) result[group_id][</span><span style="color: #800000;">"</span><span style="color: #800000;">urls</span><span style="color: #800000;">"</span><span style="color: #000000;">].append(url) </span><span style="color: #0000ff;">else</span><span style="color: #000000;">: </span><span style="color: #008000;">#</span><span style="color: #008000;">如果不在就添加進去</span> result[group_id] =<span style="color: #000000;">{ </span><span style="color: #800000;">"</span><span style="color: #800000;">codes</span><span style="color: #800000;">"</span><span style="color: #000000;">:[code,], </span><span style="color: #800000;">"</span><span style="color: #800000;">urls</span><span style="color: #800000;">"</span><span style="color: #000000;">:[url] } </span><span style="color: #008000;">#</span><span style="color: #008000;"> print(result)</span> <span style="color: #008000;">#</span><span style="color: #008000;">吧所有權限中的url字典放到session中</span> request.session[settings.PERMISSION_URL_DICT_KEY] =<span style="color: #000000;"> result </span><span style="color: #008000;">#</span><span style="color: #008000;"> # 打印的結果如下</span> <span style="color: #008000;">#</span><span style="color: #008000;"> result = {</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 1: {</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "codes": ["list", "add", "del", "edit"]</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "urls": [</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "/userinfo/",</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "/userinfo/add" ,</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "/userinfo/del(\d+)/ ",</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "/userinfo/edit(\d+)/ ",</span> <span style="color: #008000;">#</span><span style="color: #008000;"> ]</span> <span style="color: #008000;">#</span><span style="color: #008000;"> },</span> <span style="color: #008000;">#</span><span style="color: #008000;"> 2: {</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "codes": {"list", "add", "del", "edit"}</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "urls": [</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "/order",</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "/order/add" ,</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "/order/del(\d+)/ ",</span> <span style="color: #008000;">#</span><span style="color: #008000;"> "/order/edit(\d+)/ ",</span> <span style="color: #008000;">#</span><span style="color: #008000;"> ]</span> <span style="color: #008000;">#</span><span style="color: #008000;"> }</span> <span style="color: #008000;">#</span><span style="color: #008000;"> }</span></pre>
五、中間件
- 在setting里設置白名單(不用權限就可以訪問)
#白名單 VALID_URL = [ "/login/", "/admin.*/", "/index/" ]# ====rabc
PERMISSION_URL_DICT_KEY="permissions_url_dict"
PERMISSION_MENU_KEY = "menu_list"
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'rbac.middlewears.rbac.Middle', ]
- 獲取當前的url請求
- 獲取session保存的權限信息
- 循環url進行正則匹配,如果匹配成功就有權訪問,不成功就無法訪問
用中間件的時候記得要在settings里面配置一下:
#!usr/bin/env python # -*- coding:utf-8 -*- import re from django.shortcuts import render,HttpResponse,redirect from django.conf import settings class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__()</span><span style="color: #0000ff;">def</span> <span style="color: #800080;">__call__</span><span style="color: #000000;">(self, request): response </span>=<span style="color: #000000;"> None </span><span style="color: #0000ff;">if</span> hasattr(self, <span style="color: #800000;">'</span><span style="color: #800000;">process_request</span><span style="color: #800000;">'</span><span style="color: #000000;">): response </span>=<span style="color: #000000;"> self.process_request(request) </span><span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> response: response </span>=<span style="color: #000000;"> self.get_response(request) </span><span style="color: #0000ff;">if</span> hasattr(self, <span style="color: #800000;">'</span><span style="color: #800000;">process_response</span><span style="color: #800000;">'</span><span style="color: #000000;">): response </span>=<span style="color: #000000;"> self.process_response(request, response) </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> response
class Middle(MiddlewareMixin):
def process_request(self,request):
#獲取當前的url請求
current_url = request.path_info #拿到當前的路徑
# print(request.path,current_url)
#獲取Session中保存當前用戶的權限,
# request.session.get("permissions_url_list")
# 如果當前的路徑和session里面保存的url一樣就break了,如果不一樣就說明無權訪問
for url in settings.VALID_URL:
# print(url,current_url)
if re.match(url,current_url):
return None #如果url是表名單白名單里面的,就讓直接走后面的permission_dict </span>=<span style="color: #000000;"> request.session.get(settings.PERMISSION_URL_DICT_KEY) </span><span style="color: #008000;">#</span><span style="color: #008000;">在初始化的時候把url以字典的顯示存在了session里面,現在獲取的也就是一個字典了</span> <span style="color: #008000;">#</span><span style="color: #008000;"> print("==========",permission_dict)</span> flag =<span style="color: #000000;"> False </span><span style="color: #0000ff;">for</span> group_id,code_url <span style="color: #0000ff;">in</span><span style="color: #000000;"> permission_dict.items(): </span><span style="color: #0000ff;">for</span> url <span style="color: #0000ff;">in</span> code_url[<span style="color: #800000;">"</span><span style="color: #800000;">urls</span><span style="color: #800000;">"</span><span style="color: #000000;">]: regax </span>= <span style="color: #800000;">"</span><span style="color: #800000;">^{0}$</span><span style="color: #800000;">"</span><span style="color: #000000;">.format(url) </span><span style="color: #008000;">#</span><span style="color: #008000;"> print(regax,current_url)</span> <span style="color: #0000ff;">if</span><span style="color: #000000;"> re.match(regax,current_url): </span><span style="color: #008000;">#</span><span style="color: #008000;">match只要是..開頭的都能匹配到,多以的加個^和$符</span> request.permission_code_list=code_url[<span style="color: #800000;">"</span><span style="color: #800000;">codes</span><span style="color: #800000;">"</span><span style="color: #000000;">] flag </span>=<span style="color: #000000;"> True </span><span style="color: #0000ff;">break</span> <span style="color: #0000ff;">if</span> flag: <span style="color: #008000;">#</span><span style="color: #008000;">跳出外層循環</span> <span style="color: #0000ff;">break</span> <span style="color: #0000ff;">if</span> <span style="color: #0000ff;">not</span><span style="color: #000000;"> flag: </span><span style="color: #0000ff;">return</span> HttpResponse(<span style="color: #800000;">"</span><span style="color: #800000;">無權訪問</span><span style="color: #800000;">"</span><span style="color: #000000;">) </span><span style="color: #0000ff;">def</span><span style="color: #000000;"> process_response(self,request,response): </span><span style="color: #0000ff;">return</span> response</pre>