rbac: Role_Based Access Control,基於角色的權限控制正則表達式
權限:一個包含正則表達式 的url就是一個權限數據庫
目錄結構:django
rbac這個app中的文件代碼以下:session
rbac/models.py數據結構
from django.db import models # Create your models here. class User(models.Model):
# 這個User要和 app 中的 用戶信息表 一對一關聯; from rbac.models import * name = 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=128) actions = models.CharField(max_length=32) # 用於標識「增刪改查」某一操做 --- "add","delete","edit","list" group = models.ForeignKey(to="PermissionGroup",on_delete=models.CASCADE) # 可以避免頁面渲染時,判斷 <a>標籤是否存在時的 url 帶有表名 """ 所要獲得的數據結構 permission_dict : { 1:{ url:[...], actions:[...] } 2:{ url:[...], actions:[...] }, ... } # 字典中的數字鍵表明 permission_group,即權限分類(角色或者表名分類) """ def __str__(self): return self.title class PermissionGroup(models.Model): """ 做用:標識哪一個權限屬於哪一個組(或者說是哪一個表的增刪改查) """ title = models.CharField(max_length=32) def __str__(self): return self.title
rbac/service/register_permissions.pyapp
def initiate_permissions_session(request,user): """ 登錄後把權限註冊到session中 """ # 方式一:只包含 url 的列表 """ permissions = user.roles.all().values("permissions__url").distinct() # 取出當前用戶的全部權限(QuerySet;要去重) permission_list = [] for item in permissions: permission_list.append(item["permissions__url"]) request.session["permission_list"] = permission_list # 把權限列表註冊到session 中,之後直接從 session 中去取 """ # 方式二:字典 permissions = user.roles.all().values("permissions__url","permissions__actions","permissions__group_id").distinct() permissions_dict = {} for item in permissions: pgid = item.get("permissions__group_id") if pgid not in permissions_dict: permissions_dict[pgid] = { "actions":[item["permissions__actions"]], "urls":[item["permissions__url"]] } else: permissions_dict[pgid]["actions"].append(item["permissions__actions"]) permissions_dict[pgid]["urls"].append(item["permissions__url"]) request.session["permissions_dict"] = permissions_dict """ 方式二獲得的 permissions_dict 數據結構形式: { 1:{ url:[...], actions:[...] } 2:{ url:[...], actions:[...] }, ... } """ """ 登錄驗證成功後要調用這個函數 """
rbac/service/rbac.py函數
from django.utils.deprecation import MiddlewareMixin import re from django.shortcuts import redirect,HttpResponse class PermissionValid(MiddlewareMixin): """ 經過中間件校驗用戶是否有權限訪問某個url """ def process_request(self,request): current_path = request.path url_white_list = ["/login/","/reg/","/admin/.*"] # /admin/.*" 表示 全部 以 admin 開關的url # 先校驗當前的 url 是否在 白名單中 (url_white_list中有正則,不能直接用 in 判斷) for url in url_white_list: ret = re.match(url,current_path) if ret: return None # 經過校驗 # 再校驗當前用戶是否已經登錄(根據具體的登錄驗證邏輯來重構這塊的代碼) if request.user.is_anonymous: return redirect("/login/") # 跳轉到登錄頁面 """ def reg(request,current_path): permission_list = request.session.get("permission_list", []) flag = False for permission in permission_list: permission = "^%s$" % permission ret = re.match(permission, current_path) if ret: flag = True break return flag #校驗權限1(permission_list) permission_list = request.session.get("permission_list",[]) # ['/users/', '/users/add', '/users/delete/(\\d+)', 'users/edit/(\\d+)'] flag=reg(request,current_path) if not flag: return HttpResponse("沒有訪問權限!") return None """ # 校驗權限2:(permission_dict) 最後判斷用戶是否有當前url 的權限 permissions_dict = request.session["permissions_dict"] for item in permissions_dict.values(): for url in item["urls"]: ret = "^%s$"%url # 爲了讓 url 和 current_path 徹底匹配,須要在其先後加上 ^$ ret = re.match(url,current_path) if ret: request.actions = item["actions"] # 若是匹配成功,就把該當前用戶對該表的全部能進行的操做添加到 request中; # Permission表中 actions & group字段,和 PermissionGroup這個表都是爲了這一步 return None return HttpResponse("您沒有這個url的權限!")
rbac組件小結:url
1 權限粒度控制 2 3 簡單控制: 4 {% if "users/add" in permissions_list%} 5 6 7 擺脫表控制 8 9 10 更改數據庫結構 11 class Permission(models.Model): 12 title=models.CharField(max_length=32) 13 url=models.CharField(max_length=32) 14 15 action=models.CharField(max_length=32,default="") 16 group=models.ForeignKey("PermissionGroup",default=1) 17 def __str__(self):return self.title 18 19 20 21 class PermissionGroup(models.Model): 22 title = models.CharField(max_length=32) 23 24 def __str__(self): return self.title 25 26 27 登陸驗證: 28 permissions = user.roles.all().values("permissions__url","permissions__group_id","permissions__action").distinct() 29 30 構建permission_dict 31 32 permissions: 33 [ 34 35 {'permissions__url': '/users/add/', 36 'permissions__group_id': 1, 37 'permissions__action': 'add'}, 38 39 {'permissions__url': '/roles/', 40 'permissions__group_id': 2, 41 'permissions__action': 'list'}, 42 43 {'permissions__url': '/users/delete/(\\d+)', 44 'permissions__group_id': 1, 45 'permissions__action': 'delete'}, 46 47 {'permissions__url': 'users/edit/(\\d+)', 48 'permissions__group_id': 1, 49 'permissions__action': 'edit'} 50 ] 51 52 permission_dict 53 54 55 { 56 57 1: { 58 'urls': ['/users/', '/users/add/', '/users/delete/(\\d+)', 'users/edit/(\\d+)'], 59 'actions': ['list', 'add', 'delete', 'edit']}, 60 61 2: { 62 'urls': ['/roles/'], 63 'actions': ['list']} 64 65 } 66 67 68 69 中間價校驗權限: 70 permission_dict=request.session.get("permission_dict") 71 72 for item in permission_dict.values(): 73 urls=item['urls'] 74 for reg in urls: 75 reg="^%s$"%reg 76 ret=re.match(reg,current_path) 77 if ret: 78 print("actions",item['actions']) 79 request.actions=item['actions'] 80 return None 81 82 return HttpResponse("沒有訪問權限!")