权限管理组件:rbac

rbac: Role_Based Access Control,基于角色的权限控制

权限:一个包含正则表达式 的url就是一个权限

目录结构:

rbac这个app中的文件代码如下:

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.py

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组件小结:

 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("没有访问权限!")
原文地址:https://www.cnblogs.com/neozheng/p/9555444.html