權限管理組件:rbac

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("沒有訪問權限!")
相關文章
相關標籤/搜索