• 权限管理组件: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("没有访问权限!")
  • 相关阅读:
    8.25
    8.24
    8.23
    8.22
    8.21
    8.20
    8.19
    8.18
    8.17
    8.16
  • 原文地址:https://www.cnblogs.com/neozheng/p/9555444.html
Copyright © 2020-2023  润新知