drf排序过滤和权限管理介绍

drf排序过滤和权限管理介绍

排序和过滤分析

我们在重写GenericAPIView和ListModelMixin的三皈依,只要在视图类中配置了filter_backends那么他就能实现分页和过滤
内置的过滤类有(SearchFilter),排序类有(OrderingFilter)
而我们自己需要写一个类,并且继承BaseFilterBackend,重写filter_querset对象,返回的是一个querset对象,就是我们过滤或排序
既然我们继承了ListModelMixin那么他内部就有一个list方法
class ListModelMixin:
    def list(self, request, *args, **kwargs):
        # self.get_querset()所有数据,经过了self.filter_querset返回了一个querset对象,将过滤完成后的querset再赋值给一个querset对象
        queryset = self.filter_queryset(self.get_queryset())
        # 如果有分页的话那么就先走分页,在视图类中配置了分页类
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        # 如果没有分页,走正常的序列化返回
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data)

# self.filter_querset完成了过滤,当前在视图类中,self是视图函数的对象,对试图类中寻找发现没有,就需要到父类中寻找,GenericAPIView,找到filter_querset,这里有有重写的对象
    def filter_queryset(self, queryset):
        for backend in list(self.filter_backends):
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset

基于jwt的认证

from rest_framework_jwt.authentication import BaseAuthentication
from rest_framework_jwt.settings import api_settings
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
jwt_get_username_from_payload = api_settings.JWT_PAYLOAD_GET_USERNAME_HANDLER
from rest_framework_jwt.authentication import jwt_decode_handler
import jwt
from rest_framework.exceptions import AuthenticationFailed
class JWTBaseAuthentication(BaseAuthentication):  # 继承验证类基类
    def authenticate(self, request):  # 重写authenticate方法
        print(request.META)  # 打印查看
        jwt_value = request.META.get('HTTP_TOKEN')  # 获取token使用META发明方法
        try:  # 进行报错捕获,并且验证token是否合法
            payload = jwt_decode_handler(jwt_value)  
        except jwt.ExpiredSignature:  # 验证token是否过期
            raise AuthenticationFailed('token过期了')  # 返回验证类的报错信息
        except jwt.DecodeError:  # 验证是否是token错误,返回验证累的解码失败
            raise AuthenticationFailed('token解码失败')  # 返回报错
        except jwt.InvalidTokenError:  # 不知道说明错误,反正报
            raise AuthenticationFailed('反正就是不让你过,怎么滴')  # 报错信息
        user_id = payload.get('user_id')  # 将user的id返回
        return (user_id,jwt_value)  # 返回token和用户id

RBAC的介绍和使用(借鉴于https://www.cnblogs.com/niuli1987/p/9871182.html)

RBAC是什么?

  • RBAC 是基于角色的访问控制(Role-Based Access Control )在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

RBAC介绍。

  • RBAC 认为授权实际上是WhoWhatHow 三元组之间的关系,也就是WhoWhat 进行How 的操作,也就是“主体”对“客体”的操作。
    • Who:是权限的拥有者或主体(如:User,Role)。
    • What:是操作或对象(operation,object)。
    • How:具体的权限(Privilege,正向授权与负向授权)。
    • 然后 RBAC 又分为RBAC0、RBAC1、RBAC2、RBAC3

RBAC0、RBAC1、RBAC2、RBAC3简单介绍。

  • RBAC0:是RBAC的核心思想。
  • RBAC1:是把RBAC的角色分层模型。
  • RBAC2:增加了RBAC的约束模型。
  • RBAC3:其实是RBAC2 + RBAC1。

估计看完图后,应该稍微清楚一点。

下面来看个Demo。员工权限设计的模型图,以及对应关系。

关系图,以及实体设计。

表设计

在我们平常的权限系统中,想完全遵循 RBAC 模型是很难的,因为难免系统业务上有一些差异化的业务考量,所以在设计之初,不要太理想,太追求严格的 RBAC 模型设计,因为这样会使得你的系统处处鸡肋,无法拓展。

所以在这里要说明一下, RBAC 是一种模型,是一种思想,是一种核心思想,但是就思想而言,不是要你完全参照,而是你在这个基础之上,融入你自己的思想,赋予你的业务之上,达到适用你的业务。所以要批评一下那些说:“RBAC模型是垃圾,按照它思路去执行,结果无法拓展。”之类话语的人。那是你自己不会变通。

背景需求:

需要在“权限”=>“角色”=>“用户”之间,在赋予一个特殊的角色“客服”,这个需求比较常见,我一个用户想把我的权限分配到“客服”角色上,然后由几个“客服”去操作对应的业务流程。比如我们的天猫,淘宝商家后天就是如此,当店铺开到一定的规模,那么就会有分工。

A客服:负责打单填写发货单。

B~E客服:负责每天对我们说“亲,您好。祝亲生活愉快!”,也就是和我们沟通交流的客服。

F~H:负责售后。

... ...

那么这些客服也是归属到这个商家下面去。而且每个商家可能都有类似的客服,分工完全靠商家自己去分配管理

这样的系统,融合我们的权限控制,关键要看“客服”用户的添加是在哪添加,如果是由客服直接添加,不走我们的统一注册流程,那建议不要融合到上面这一套 权限、角色、用户之间去,而是给用户再多一个绑定,把多个用户绑定到客服下,并且给客服赋予对应的权限。

1、权限赋予:

权限赋予是把当前用户的权限拉出来,然后分配的客服可以小于等于当前用户的权限。

2、权限加载:

正常的加载权限,当用户登录后,并且第一次使用权限判断的时候, Shiro 会去加载权限。

3、权限判断:

走正常用户权限判断,但是数据操作需要判断是不是当前归属的用户的数据,其实这个是属于业务层,就算你不是客服,也是需要判断。

4、禁用|启用:

禁用启用,也是正常的用户流程,添加到禁用列表里,如果被禁用,就无法操作任何内容。

总之:不要让框框架架来限制你的业务,也不要让你的业务局限于框框架架。但是也不推荐你去改动框框架架,而是基于框框架架做业务封装。

1.RBAC是基于角色的访问控制(Role-Based Access Control)在RBAC中,权限与角色相关联,用户通过适当角色的成员而得到这些角色的权限,这就极大地简化了权限的管理,这些管理都是层级相互依赖的,权限赋予给角色,而角色又赋予用户,这样就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而吧角色又赋予用户,这样的权限涉及很清楚,管理起来很方便。

2.RBAC权限管理的模式,最适合公司内部的管理系统,不适合对外互联网用户的系统

3.DVAdmin:http://demo.django-vue-admin.com/
4.试用请查看:https://gitee.com/liqianglog/django-vue-admin

RBAC认为授权实际上是who,what,how三元组之间的关系,也就是who对what进行how的操作,也就是"主体"对"客体"的操作。
who 是权限的拥有者或主体(如:User,Role)
what 是操作或对象(operation,object)
how 具体的权限(Privilege,正向授权与反向授权)
然后RBAC又分为RBAC0、RBAC1、RBAC2、RBAC3
RBAC0 RBAC的核心
RBAC1 基于角色的分层模型
RBAC2 是RBAC的约束模型
RBAC3 就是RBAC1+RBAC2

RBAC0、RBAC1、RBAC2、RBAC3的介绍详细篇:https://www.cnblogs.com/Code-Is-Fun/p/14998830.html

  • RBAC的三种模型与拓展(图片无法显示请担待)

    • 一、RBAC模型是什么?

      RBAC是一套成熟的权限模型。在传统权限模型中,我们直接把权限赋予用户。而在RBAC中,增加了“角色”的概念,我们首先把权限赋予角色,再把角色赋予用户。这样,由于增加了角色,授权会更加灵活方便。在RBAC中,根据权限的复杂程度,又可分为RBAC0、RBAC1、RBAC2、RBAC3。其中,RBAC0是基础,RBAC1、RBAC2、RBAC3都是以RBAC0为基础的升级。我们可以根据自家产品权限的复杂程度,选取适合的权限模型。

    • 二、基本模型RBAC0

      • 解析:RBAC0是基础,很多产品只需基于RBAC0就可以搭建权限模型了。在这个模型中,我们把权限赋予角色,再把角色赋予用户。用户和角色,角色和权限都是多对多的关系。用户拥有的权限等于他所有的角色持有权限之和。
      • 举例:譬如我们做一款企业管理产品,如果按传统权限模型,给每一个用户赋予权限则会非常麻烦,并且做不到批量修改用户权限。这时候,可以抽象出几个角色,譬如销售经理、财务经理、市场经理等,然后把权限分配给这些角色,再把角色赋予用户。这样无论是分配权限还是以后的修改权限,只需要修改用户和角色的关系,或角色和权限的关系即可,更加灵活方便。此外,如果一个用户有多个角色,譬如王先生既负责销售部也负责市场部,那么可以给王先生赋予两个角色,即销售经理+市场经理,这样他就拥有这两个角色的所有权限。
    • 三、角色分层模型RBAC1

      • 解析:RBAC1建立在RBAC0基础之上,在角色中引入了继承的概念。简单理解就是,给角色可以分成几个等级,每个等级权限不同,从而实现更细粒度的权限管理。
      • 举例:基于之前RBAC0的例子,我们又发现一个公司的销售经理可能是分几个等级的,譬如除了销售经理,还有销售副经理,而销售副经理只有销售经理的部分权限。这时候,我们就可以采用RBAC1的分级模型,把销售经理这个角色分成多个等级,给销售副经理赋予较低的等级即可。
    • 四、角色限制模型RBAC2

      • 解析:RBAC2同样建立在RBAC0基础之上,仅是对用户、角色和权限三者之间增加了一些限制。这些限制可以分成两类,即静态职责分离SSD(Static Separation of Duty)和动态职责分离DSD(Dynamic Separation of Duty)。具体限制如下图:
      • 举例:还是基于之前RBAC0的例子,我们又发现有些角色之间是需要互斥的,譬如给一个用户分配了销售经理的角色,就不能给他再赋予财务经理的角色了,否则他即可以录入合同又能自己审核合同;再譬如,有些公司对角色的升级十分看重,一个销售员要想升级到销售经理,必须先升级到销售主管,这时候就要采用先决条件限制了。
    • 五、统一模型RBAC3

      • 解析:RBAC3是RBAC1和RBAC2的合集,所以RBAC3既有角色分层,也包括可以增加各种限制。
      • 举例:这个就不举例了,统一模型RBAC3可以解决上面三个例子的所有问题。当然,只有在系统对权限要求非常复杂时,才考虑使用此权限模型。
    • 六、基于RBAC的延展——用户组

      • 解析:基于RBAC模型,还可以适当延展,使其更适合我们的产品。譬如增加用户组概念,直接给用户组分配角色,再把用户加入用户组。这样用户除了拥有自身的权限外,还拥有了所属用户组的所有权限。
      • 举例:譬如,我们可以把一个部门看成一个用户组,如销售部,财务部,再给这个部门直接赋予角色,使部门拥有部门权限,这样这个部门的所有用户都有了部门权限。用户组概念可以更方便的给群体用户授权,且不影响用户本来就拥有的角色权限。
    • 七、总结

      • 基于角色的访问控制 (RBAC) 是一种围绕角色和权限定义的策略中立的访问控制机制。RBAC 的组件(例如角色权限、用户角色和角色角色关系)使执行用户分配变得简单。NIST 的一项研究表明,RBAC 可以满足商业和政府组织的许多需求。RBAC 可用于在拥有数百个用户和数千个权限的大型组织中促进安全管理。尽管 RBAC 与 MAC 和 DAC 访问控制框架不同,但它可以毫不费力地执行这些策略。

ACL、RBAC、ABAC(PBAC、CBAC)权限控制的介绍

  • ACL(Access Control List,访问控制列表)

    • 它是由一系列条件规则(及描述性命令)的方式授予用户或角色对指定对象执行制定操作的权限。
    • ACL权限为白名单授权机制,即允许用户或角色对指定对象执行指定操作。ACL权限控制方式简单明了,可实现精准授权。
    • 用户表,权限表,中间表,给用户授予某些权限
  • DAC(Discretionary Access Control自主访问控制)

    • 系统会识别用户,然后根据被操作对象(subject)的权限控制列表(ACL: Access Control List)或者权限控制矩阵(ACL: Access Control Matrix)的信息来决定用户是否能对其进行那些操作,例如读取或修改
    • 而拥有对象权限的用户,又可以将该对象的权限分配给其他用户,所以称之为"自主(Discretionary)"控制
    • 这种设计最常见的应用就是文件洗用的权限设计,如微软的NTFS.
    • DAC最大的缺陷就是对权限控制比较分散,不便于管理,比如无法简单的将一组文件设置为统一的全线开放给一群用户
  • 强制访问控制(MAC: Mandatory Access Control)

    • MAC是为了弥补DAC权限控制过于分散的问题而诞生的。在MAC的设计中,每一个对象都有一些权限标识,每个用户同样也会有一些权限标识,而用户能否对该对象进行操作取决于双方的权限标识的关系,这个限制判断通常是由系统硬性限制的。比如在影视作品中我们经常能看到特工在查询机密文件时,屏幕提示需要“无法访问,需要一级安全许可”,这个例子中,文件上就有“一级安全许可”的权限标识,而用户并不具有。
    • MAC非常适合机密机构或者其他等级观念强烈的行业,但对于类似商业服务系统,则因为不够灵活而不能适用。
  • 基于角色的访问控制(RBAC: Role-Based Access Control)

    • 将用户与角色对接然后角色与对象的权限对接
    • 因为DAC和MAC的诸多限制,于是诞生了RBAC,并且成为了迄今为止最为普及的权限设计模型
    • RBAC用户和权限之间引入了"角色(Role)"的概念(暂时忽略Session这个概念)
    • 每个用户关联一个或多个角色,每个角色关联一个或多个权限,从而可以实现了非常灵活的权限管理。角色可以根据实际业务需求灵活创建,这样就省去了每新增一个用户就要关联一遍所有权限的麻烦。简单来说RBAC就是:用户关联角色,角色关联权限。另外,RBAC是可以模拟出DAC和MAC的效果的。
  • RBAC+ACL django,公司用的比较多

  • 基于属性的权限验证(ABAC:Attribute-Based Access Control),又被称为PBAC(Policy-Based Access Control,基于策略的访问控制),CBAC(Claims-Based Access Control,基于声明的访问控制)

    • ABAC被一些人称为全县系统设计的未来

    • 不同于常见的将用户通过某种方式关联到权限的方式,ABAC则是通过动态计算一个或一组属性来是否满足某种条件来进行授权判断(可以编写简单的逻辑)。属性通常来说分为四类:用户属性(如用户年龄),环境属性(如当前时间),操作属性(如读取)和对象属性(如一篇文章,又称资源属性),所以理论上能够实现非常灵活的权限控制,几乎能满足所有类型的需求。

    • 例如规则:“允许所有班主任在上课时间自由进出校门”这条规则,其中,“班主任”是用户的角色属性,“上课时间”是环境属性,“进出”是操作属性,而“校门”就是对象属性了。为了实现便捷的规则设置和规则判断执行,ABAC通常有配置文件(XML、YAML等)或DSL配合规则解析引擎使用。XACML(eXtensible Access Control Markup Language)是ABAC的一个实现,但是该设计过于复杂,我还没有完全理解,故不做介绍。

    • 总结一下,ABAC有如下特点:

      • 集中化管理
      • 可以按需求实现不同颗粒度的权限控制
      • 不需要预定判断逻辑,减轻了权限系统的维护成本,特别是在需求经常变化的系统中
      • 定义权限时,不能直观看出用户和对象间的关系
      • 规定如果稍微复杂一点,或者设计混乱,会给管理者维护和追查带来麻烦
      • 权限判断需要实施执行,规则过多看导致性能问题
    • 因为大部分系统对权限控制并没有过多的需求,而ABAC的管理相对来说太复杂了。所以流行的还是RBACKubernetes便因为ABAC太难用,在1.8版本里引入了RBAC的方案

  • 来自于:https://www.cnblogs.com/lijiejoy/p/15451583.html

casbin权限控制(acl\rbac...)

  • 概念

    • 权限管理几乎是每个系统或服务都会直接或简介设计的部分,权限管理保障了资源(大部分时候就是数据)的安全,权限管理一般都是业务强关联,每当有新的业务或者业务变化时,不能将经理完全放在业务实现上,权限的调度往往耗费大量精力
    • 其实权限的本质没有那么复杂,只是对访问的控制而已,再加上简单的权限模型,权限模型之所以能够简单,就是因为权限管理本身并不复杂,只是在和具体业务结合时,出现了各种各样的访问控制场景,才显得复杂。
  • PERM模型

    • PERM(Policy,Request,Matchers)模型很简单,但是反映了权限的本质-访问控制
      • Policy:定义权限的规则
      • Effect:定义组合了多个Policy之后的结果,allow/deny
      • Request:访问请求,也就是谁想操作什么
      • Matcher:判断Request是否满足Policy
  • casbin权限库

    • casbin使用了PERM模型来表达权限,并且提供了简单直接的API
    import casbin
    
    e = casbin.Enforcer("./model.conf", "./policy.csv")
    
    sub = "jsoeph"  # 想要访问资源的用户
    obj = "book"  # 将要被访问的资源
    act = "get"  # 用户对资源进行的操作
    
    
    # 自己写acl的控制
    # 当前用户id,去权限和用户表查询即可,有记录就是有权限
    
    # 自己写rbac
    # 当前用户id,找到他的角色,根据角色拿出权限,判断当前访问有没有
    
    
    if e.enforce(sub, obj, act):
        # 允许alice读取data1
        print(f'{sub}对{obj}有{act}权限')
    else:
        # 拒绝请求,抛出异常
        print(f'{sub}对{obj}没有有{act}权限')
    
    • 核心概念之model file,用来定义具体的权限模型,目前支持的模型基本覆盖了常见的所有场景
    [request_definition]
    r = sub, obj, act
    
    [policy_definition]
    p = sub, obj, act
    
    [policy_effect]
    e = some(where (p.eft == allow))
    
    [matchers]
    m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
    
    • 核心概念之Policy file,定义具体的策略,权限的检查就是基于定义的model file和policy file来完成的,相对于model file定义规则,policy file中定义的就是具体的内容
    p,alice,data1,read
    p,bob,data2,write
    p,lqz,book,get
    

后台管理implui的介绍和使用

  • django admin自带了权限控制,但是是前后端混合的,我们可以进行二次开发,开发出公司内部的自动化运行,自动化测试,认识管理系统、订单系统,财会系统等但是样子不好看
  • 所有就有对django amdin进行美化
    • xadmin(已经不使用,过时了)
    • simpleui(正当红,大多使用这个)
  • settings.py
import time

SIMPLEUI_CONFIG = {
    'system_keep': False,
    'menu_display': ['我的首页', '图书管理','权限认证', '多级菜单测试', '动态菜单测试'],  # 开启排序和过滤功能, 不填此字段为默认排序和全部显示, 空列表[] 为全部不显示.
    'dynamic': True,  # 设置是否开启动态菜单, 默认为False. 如果开启, 则会在每次用户登陆时动态展示菜单内容
    'menus': [
        {
            'name': '我的首页',
            'icon': 'fas fa-code',
            'url': '/index/',

        },
        {
            'app': 'app01',
            'name': '图书管理',
            'icon': 'fas fa-code',
            'models': [
                {
                    'name': '用户',
                    'icon': 'fa fa-user',
                    'url': 'app01/userinfo/'
                },
                {
                    'name': '图书',
                    'icon': 'fa fa-user',
                    'url': 'app01/book/'
                },
                {
                    'name': '出版社',
                    'icon': 'fa fa-user',
                    'url': 'app01/publish/'
                },
            ]
        },
        {
            'app': 'auth',
            'name': '权限认证',
            'icon': 'fas fa-user-shield',
            'models': [{
                'name': '用户',
                'icon': 'fa fa-user',
                'url': 'auth/user/'
            }]
        },
        {
            # 自2021.02.01+ 支持多级菜单,models 为子菜单名
            'name': '多级菜单测试',
            'icon': 'fa fa-file',
            # 二级菜单
            'models': [
                {
                    'name': '百度',
                    'icon': 'far fa-surprise',
                    # 第三级菜单 ,
                    'models': [
                        {
                            'name': '爱奇艺',
                            'url': 'https://www.iqiyi.com/dianshiju/'
                            # 第四级就不支持了,element只支持了3级
                        },
                        {
                            'name': '百度问答',
                            'icon': 'far fa-surprise',
                            'url': 'https://zhidao.baidu.com/'
                        }
                    ]
                },
                {
                    'name': 'lqz',
                    'url': 'https://www.wezoz.com',
                    'icon': 'fab fa-github'
                }]
        },
        {
            'name': '动态菜单测试',
            'icon': 'fa fa-desktop',
            'models': [{
                'name': time.time(),
                'url': 'http://baidu.com',
                'icon': 'far fa-surprise'
            }]
        }]
}


SIMPLEUI_LOGIN_PARTICLES = False
SIMPLEUI_HOME_INFO = False

admin.py

from django.contrib import admin

# Register your models here.

from .models import *


@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    list_display = ('id', 'title', 'price')

    # 增加自定义按钮
    actions = ['make_copy', ]
    def make_copy(self, request, queryset):
        print('adsfasdf')
    make_copy.short_description = '自定义按钮'
    # # icon,参考element-ui icon与https://fontawesome.com
    make_copy.icon = 'fas fa-audio-description'
    # # 指定element-ui的按钮类型,参考https://element.eleme.cn/#/zh-CN/component/button
    make_copy.type = 'danger'
    make_copy.confirm = '你是否执意要点击这个按钮?'



admin.site.register(UserInfo)
admin.site.register(Publish)
posted @ 2022-10-13 19:22  Joseph-bright  阅读(290)  评论(0编辑  收藏  举报