Drf从入门到精通十(基于JWT自定义认证类、排序与过滤源码分析、RBAC介绍与使用、SimpleUI介绍与使用)

文章目录

  • 一、基于JWT自定义认证类
  • 二、排序和过滤源码分析
  • 三、RBAC的介绍与使用
    • 1)ACL、RBAC、ABAC(PBAC、CBAC)权限控制介绍
    • 2)Casbin模块
  • 四、后台管理Simple UI的介绍与使用

一、基于JWT自定义认证类

上篇文章我们刚讲完基于Session的JWT认证类 那我们现在研究研究怎样实现JWT的认证类 就从它的认证类下手JSONWebTokenAuthentication
点击进去发现没有authenticate方法 但是它继承了BaseJSONWebTokenAuthentication 再进去看第一个就是我们要找的authenticate方法了

源码展示

class BaseJSONWebTokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        jwt_value = self.get_jwt_value(request)			# 获取前端传入的信息request
        if jwt_value is None:							# 判断是否有值 
            return None

        try:		# 最核心的就是JWT的核心代码了
            payload = jwt_decode_handler(jwt_value)		# 解码信息获取Token 去验证
        except jwt.ExpiredSignature:
            msg = _('Signature has expired.')			# 签名时间过期超时
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding signature.')		# 错误的解码方式签名
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:					# 认证失败
            raise exceptions.AuthenticationFailed()

        user = self.authenticate_credentials(payload)	# 判断是否跟库里面的用户一致 返回用户

        return (user, jwt_value)						# 返回当前登录用户 与token

我们看懂了这个源码之后我们就知道了怎样重写JWT认证类了 重写它的authenticate即可

class Base(BaseAuthentication):
    def authenticate(self, request):
        try:
            rest_token = request.META.get('HTTP_AUTHORIZATION')  # 获取传入的Token
            jwt_name, token = rest_token.split(' ')     # 取出token中的空格
            payload = jwt_decode_handler(token)  # 获取数据库的Token
        except jwt.ExpiredSignature:
            msg = ('签名时间已经过期啦!!!')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = ('错误的解放方式')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed()
        user = UserInfo.objects.filter(pk=payload.get('user_id')).first()
        return user, token

	'''
		也可以直接返回Payload就不用走数据库查询 加快效率
		return (payload, token)
		
		配置视图认证类
			class JwtView(APIView):
    			authentication_classes = [Base, ]
	'''

Drf从入门到精通十(基于JWT自定义认证类、排序与过滤源码分析、RBAC介绍与使用、SimpleUI介绍与使用)_第1张图片

二、排序和过滤源码分析

首先回想我们的排序与过滤 想使用他们两个必须继承GenericAPIView + ListModelMixin及其子类 排序类OrderingFiler
只要在视图类中配置filter_backends、filterset_fields&search_fields就可以实现过滤和排序了 内置的过滤类SearchFilter
Django-filter 自定义写一个类 继承BaseFilterBackend 重写filter_queryset 返回的queryset对象 就是过滤或排序后的数据了
再次我们使用排序与过滤的时候只会在获取信息的时候才会用到 所以我们进到源码中查找list方法就好了

def list(self, request, *args, **kwargs):
        # self.get_queryset()所有数据,经过了self.filter_queryset返回了qs
        # self.filter_queryset完成的过滤
        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_queryset完成了过滤,当前在视图类中,self是视图类的对象,去视图类中找没找到,去父类---》GenericAPIView---》filter_queryset
    
        def filter_queryset(self, queryset):
            for backend in list(self.filter_backends):
                queryset = backend().filter_queryset(self.request, queryset, self)
            return queryset
        
 '''
	-写的过滤类要重写filter_queryset,返回qs(过滤或排序后)对象
    -后期如果不写过滤类,只要在视图类中重写filter_queryset,在里面实现过滤也可以
 '''

三、RBAC的介绍与使用

什么是RBAC?

  • RBAC 是基于角色的访问控制(Role-Based Access Control )在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。
  • RBAC权限管理的模式,最适合公司内部的管理系统,不适合对外互联网用户的系统
  • Django的后台管理Admin就自带了RBAC的权限,通过Auth模块实现的,比普通RBAC更高级一些就是我们迁移表模型自动创建的
  • 很多公司写后台管理使用Django,使用Django的Admin二次开发,不用写权限了,快速加功能即可
	 1. auth_user 					用户表
	 2. auth_group					角色表
	 3. auth_permission 			权限表
	 4. auth_user_groups 			用户与角色中间表
	 5. auth_group_permissions 		角色与权限中间表
	 6. auth_user_user_permissions 	用户与权限中间表

Drf从入门到精通十(基于JWT自定义认证类、排序与过滤源码分析、RBAC介绍与使用、SimpleUI介绍与使用)_第2张图片

快速体验Django Admin的RBAC的权限控制

创建好表模型
	class UserInfo(models.Model):
	    username = models.CharField(max_length=32, verbose_name='名称')
	    password = models.CharField(max_length=32, verbose_name='密码')
	
	    class Meta:
	        verbose_name_plural = '用户信息表'
	
	    def __str__(self):
	        return self.username

通过createsuperuser进入后台新建用户以及其他信息 可以创建组表示这一组里面的角色有什么权限
Drf从入门到精通十(基于JWT自定义认证类、排序与过滤源码分析、RBAC介绍与使用、SimpleUI介绍与使用)_第3张图片

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

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

     将用户或组等使用者直接与对象的权限对接
     比如张三只有看抖音发抖音的权限 没有开直播的权限 交给第三张中间表来控制权限授予用户的角色
    
  • RBAC(Role-Based Access Control,基于角色的访问控制)

     将用户与角色对接 然后角色与对象的权限对接 就是跟Django的用法一样 本质就是RBAC+ACL 公司用的比较多
    
  • ABAC(Attribute-Based Access Control,基于属性的访问控制)

     ABAC(Attribute-Based Access Control,基于属性的访问控制)又称为PBAC(Policy-Based Access Control,基于策略的访问控制)
     CBAC(Claims-Based Access Control,基于声明的访问控制),传统的ACL RBAC的架构是 {subject action object},而ABAC的架构是
     {subject action object contextual},且为他们添加了parameter(参数)----简单说就是给单个权限再加上属性双重认证的感觉
    

2)Casbin模块

这个模块支持个个语言 专门做权限控制的模块(ACL RBAC ABAC) 方便我们快速做权限控制
安装Casbin

pip install casbin

根据casbin的要求需要创建两个文件一个model 一个policy 做一个最简单的ACL模型 就可以快速测试出有没有权限了
Casbin网站:https://docs.casbin.cn/zh/docs/supported-models

创建自定义py文件

import casbin

e = casbin.Enforcer("./model.conf", "./policy.csv")

sub = "alice"  # 想要访问资源的用户
obj = "data1"  # 将要被访问的资源
act = "read"  # 用户对资源进行的操作

if e.enforce(sub, obj, act):
    # 允许alice读取data1
    print('有权限')
else:
    # 拒绝请求,抛出异常
    print('没有权限')

model.conf

[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.csv

p, alice, data1, read
p, bob, data2, write
p, data2_admin, data2, read
p, data2_admin, data2, write
g, alice, data2_admin

Drf从入门到精通十(基于JWT自定义认证类、排序与过滤源码分析、RBAC介绍与使用、SimpleUI介绍与使用)_第4张图片

四、后台管理Simple UI的介绍与使用

Django-admin自带了权限控制 但是是前后端混合的 我们可以去二次开发 开发出公司内部的自动化运行 自动化测试 人事管理系统
但是他的界面样子UI不好看 所以我们现在就要对django-admin进行美化有两个主流 Xadmin(已过时) SimpleUI(正红)

或者是基于Drf+Vue 自己写前后端分离的权限管理 在Go源里面使用Go-Vue-Admin

安装

pip install django-simpleui

用pip或者源码方式安装simpleui后 在自己项目的settings.py文件中INSTALLED_APPS的第一行加入

INSTALLED_APPS = [		
    'simpleui',			# 一定要注册在第一行!!!
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'rest_framework',
]

然后这个时候访问我们的admin接口就会得到一个全新的admin系统 然后还可以进行美化修改主题以及字体大小…
SimpleUI新手快速上手指南网站:https://simpleui.72wo.com/docs/simpleui/quick.html#%E7%9B%AE%E5%BD%95
Drf从入门到精通十(基于JWT自定义认证类、排序与过滤源码分析、RBAC介绍与使用、SimpleUI介绍与使用)_第5张图片

自定义左侧的菜单栏 settings.py

import time

SIMPLEUI_CONFIG = {
    'system_keep': False,
    'menu_display': ['Simpleui', '信息管理',  '权限认证', '多级菜单测试', '动态菜单测试'],  # 开启排序和过滤功能, 不填此字段为默认排序和全部显示, 空列表[] 为全部不显示.
    'dynamic': True,  # 设置是否开启动态菜单, 默认为False. 如果开启, 则会在每次用户登陆时动态展示菜单内容
    'menus': [{
        'name': 'Simpleui',
        'icon': 'fas fa-code',
        'url': 'https://blog.csdn.net/MeiJin_',
        # 浏览器新标签中打开
        'newTab': True,
    }, {
        'app': 'app01',
        'name': '信息管理',
        'icon': 'fas fa-code',
        'models': [
            {
                'name': '用户信息',
                'url': 'app01/userinfo/',
                'icon': 'far fa-surprise'
            },
            {
                'name': '书籍信息',
                'url': 'app01/books/',
                'icon': 'far fa-surprise'
            },
            {
                'name': '出版社信息',
                'url': 'app01/publish/',
                'icon': 'far fa-surprise'
            },
        ]
    },
        {
            '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': 'Baidu',
                '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': '内网穿透',
                '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'
            }]
        }]
}

自定义按钮 admin.py

@admin.register(Books)
class BookAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'price', 'author')		# 字段必须是模型中存在的字段
    #
    # 增加自定义按钮
    actions = ['make_copy',]		# 一定要与下方的函数名对称

    def make_copy(self, request, queryset):
        print('我是自定义的按钮')			# 点击按钮要执行的事件
    #
    # # 显示的文本,与django admin一致
    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'
    #
    # # 给按钮追加自定义的颜色
    # custom_button.style = 'color:black;'
	
	make_copy.confirm = '你是否执意要点击这个按钮?'     # 弹窗提示按钮

Drf从入门到精通十(基于JWT自定义认证类、排序与过滤源码分析、RBAC介绍与使用、SimpleUI介绍与使用)_第6张图片

技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请点点赞收藏+关注谢谢支持 !!!

你可能感兴趣的:(Drf,python,drf,SinpleUi,RBAC,django)