權限管理
建立一個rbac和app的應用,這個rbac主要是用來存放權限的,全稱叫作基於角色權限控制
1、先看配置文件合適不,給建立的rbac在配置文件裏面設置一下
找到INSTALLED_APPS=【'rbac'】
2、設計表結構
models中建立類:五個類,七張表
角色表:
用戶表:
權限表:html
組表:python
菜單表:django
角色表和權限表是多對多的關係(一個角色能夠有多個權限,一個權限能夠對應多個角色)
用戶表和角色表是多對多的關係(一個用戶能夠有多個角色,一個角色有多個用戶)session
因此有會多生成兩張關係表app
一個菜單下面有多個組函數
一個組下面有多個菜單post
一個菜單下面有多個權限this
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) # 創建用戶表和角色表的多對多關係 def __str__(self): return self.title class Meta: verbose_name_plural = "角色表" 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) #新添加的字段記得設置默認值 def __str__(self): return self.title class Meta: '''中文顯示''' verbose_name_plural = "權限表" 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) #創建用戶和角色的多對多關係 def __str__(self): return self.username class Meta: verbose_name_plural = "用戶表"
3、經過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)
4、編寫登陸
用戶登陸後:
獲取當前用戶具備的全部角色
獲取當前用戶具備的全部權限(而且去重)url
#獲取當前的用戶對象 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裏
一、能夠建一個server的包,在裏面建一個初始化的init_perssion.py文件
二、定義函數spa
#!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: ''' #user.roles.all()獲取當前用戶的全部角色 #獲取當前用戶的全部權限 permission_list = user.roles.all().values( "permissions__id", "permissions__title", #用戶列表 "permissions__url", #url "permissions__menu_gp", #組內菜單id,若是爲null表示是菜單 "permissions__codes", "permissions__group_id", "permissions__group__menu__title", #菜單名稱 "permissions__group__menu__id" #菜單id ).distinct() print("-----------------",permission_list) #菜單相關 sub_permisson_list = [] for item in permission_list: tpl = { "id":item["permissions__id"], "title":item["permissions__title"], "url":item["permissions__url"], "menu_group_id":item["permissions__group_id"], "menu_id":item["permissions__group__menu__id"], "menu_title":item["permissions__group__menu__title"] } sub_permisson_list.append(tpl) request.session[settings.PERMISSION_MENU_KEY] = sub_permisson_list # 一、去掉不是菜單的url # 菜單操做 # menu_list = [] # for item in permission_list: # if not item["permissions__is_mune"]: # 若是不是菜單就繼續 # continue # else: # 不然是菜單的話就把菜單添加到列表裏面 # 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.PERMISSION_MENU_KEY] = menu_list #吧全部的菜單都放在session裏面 # print("xcvxvxv", menu_list) # 權限相關 result = {} for item in permission_list: group_id = item["permissions__group_id"] url =item["permissions__url"] code = item["permissions__codes"] if group_id in result: #若是在說明url和code已經生成了 result[group_id]["codes"].append(code) result[group_id]["urls"].append(url) else: #若是不在就添加進去 result[group_id] ={ "codes":[code,], "urls":[url] } # print(result) #吧全部權限中的url字典放到session中 request.session[settings.PERMISSION_URL_DICT_KEY] = result # # 打印的結果以下 # result = { # 1: { # "codes": ["list", "add", "del", "edit"] # "urls": [ # "/userinfo/", # "/userinfo/add" , # "/userinfo/del(\d+)/ ", # "/userinfo/edit(\d+)/ ", # ] # }, # 2: { # "codes": {"list", "add", "del", "edit"} # "urls": [ # "/order", # "/order/add" , # "/order/del(\d+)/ ", # "/order/edit(\d+)/ ", # ] # } # }
5、中間件
- 在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__() 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 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 = request.session.get(settings.PERMISSION_URL_DICT_KEY) #在初始化的時候把url以字典的顯示存在了session裏面,如今獲取的也就是一個字典了 # print("==========",permission_dict) flag = False for group_id,code_url in permission_dict.items(): for url in code_url["urls"]: regax = "^{0}$".format(url) # print(regax,current_url) if re.match(regax,current_url): #match只要是..開頭的都能匹配到,多以的加個^和$符 request.permission_code_list=code_url["codes"] flag = True break if flag: #跳出外層循環 break if not flag: return HttpResponse("無權訪問") def process_response(self,request,response): return response