DRF-源码解析-3-权限流程:drf的权限源码解析,drf的权限流程。

在这里插入图片描述

一、代码的准备

视图:

class TestAPIView(APIView):
    authentication_classes=[MyJWTAuthentication]
    permission_classes = [AdminPermission,]
    def get(self,request)
        return Respponse({'code':200,'msg':'测试通过'})

路由:

path('test/',views.TestAPIView.as_view())

请求方式:GET

认证的配置:

#1、全局配置:settings.py
REST_FRAMEWORK = {
    #1、全局认证
    'DEFAULT_AUTHENTICATION_CLASSES':['authen.authentication.MyJWTAuthentication'],
    #2、全局的权限
    'DEFAULT_PERMISSION_CLASSES':['authen.permission.AdminPermission']
}

#2、局部配置:视图类的类变量
class TestAPIView(APIView):
	authentication_classes=[MyJWTAuthentication]
    permission_classes = [AdminPermission]

token:

import jwt
from django.conf import settings
import time


def create_token(user_id: int, timeout=None):
    '''
    :param user_id: 传递用户的id
    :param timeout: token有效时间,默认是一天
    :return:
    '''
    has_exp = hasattr(settings,'JWT_EXPIRATION_DELTA')
    if has_exp:
        jwt_exp = getattr(settings,'JWT_EXPIRATION_DELTA')
    else:
        jwt_exp = 24*60*60
    if timeout == None:
        #没有指定过期时间,就使用配置的时间戳
        timeout = jwt_exp
    elif type(timeout) != int:
        #传递的类型有误,使用配置中的时间戳
        timeout = jwt_exp

    payload = {'user_id': user_id}
    salt = settings.SECRET_KEY  # 加密的盐
    # 构造header
    headers = {
        'type': 'jwt',
        'alg': 'HS256'
    }

    now_datetime = time.time()
    payload['exp'] = now_datetime + timeout  # token过期时间,时间戳
    # print(payload)
    token = jwt.encode(payload=payload, key=salt, algorithm="HS256", headers=headers).decode('utf-8')
    return token

认证类的书写:

from rest_framework.authentication import BaseAuthentication
class MyJWTAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # 获取token
        token = request.META.get("HTTP_TOKNE")  # 从请求头中获取
        if not token:
            token = request.COOKIES.get('token')  # 从cookies中获取token
        if not token:
            msg = '没有携带token'
            raise AuthenticationFailed({'code':410,'error':'没有携带token'})
        '''
        1、切割
        2、解密第二段/判断过期
        3、验证第三段合法性
        '''
        # 导入settings中的字符串做盐
        salt = settings.SECRET_KEY
        payload = None
        try:
            payload = jwt.decode(token, salt, True)
            #获取用户信息
            user = models.UserModel.objects.filter(id=payload.get('user_id'),is_enable=True).first()
            if user:
                return (user, token)
                # request.user,request.auth
            else:
                raise AuthenticationFailed({'code':410,'error':'token有问题'})
        except exceptions:
            msg = 'token有问题,请重新登录'
            raise AuthenticationFailed({'code': 410, 'error': msg})

权限类书写:

from rest_framework.permissions import BasePermission
from rest_framework import exceptions
from django.contrib.auth.models import AnonymousUser
class  AdminPermission(BasePermission):
    message='当前用户没有管理员权限'

    def has_permission(self,request,view):
        #view是视图类的对象,拿到视图类的东西
        #拿到token解析出来的用户的权限
        user = request.user
        if type(user) == AnonymousUser or user==None:
            self.message = '没有携带token'
            return False

        if user.role == 1:
            #权限是1,管理员时,才能访问接口
            return True
        else:
            #其他权限无法访问
            return False

二、具体的流程

1、TestAPIView的as_view方法,当前实例对象没有,找父类的APIView的as_view

@classmethod
def as_view(cls, **initkwargs):
    #1、调用APIView父类的as_view方法
    view = super().as_view(**initkwargs)
    view.cls = cls
    view.initkwargs = initkwargs
    #2、去除掉csrf校验
    return csrf_exempt(view)

2、APIView的as_view是调用父类View的as_view方法

@classonlymethod
def as_view(cls, **initkwargs):
    def view(request, *args, **kwargs):
        self = cls(**initkwargs)
        self.setup(request, *args, **kwargs)
        if not hasattr(self, 'request'):
            raise AttributeError(
                "%s instance has no 'request' attribute. Did you override "
                "setup() and forget to call super()?" % cls.__name__
            )
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs
    return view
 
#返回的是闭包view,
#view的功能就是self.dispatch()方法

3、as_view主要返回闭包,关于self.dispatch()方法

4、self是TestAPIView , 没有dispatch方法,调用父类APIView的dispatch方法

#简化后的源码

    def dispatch(self, request, *args, **kwargs):
        #处理url中的参数
        self.args = args
        self.kwargs = kwargs
        #构建drf的request对象
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            #认证、权限、限流的执行
            self.initial(request, *args, **kwargs)

            #通过反射来执行TestAPIView中的get、post等方法
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
			#视图函数执行结果
            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

5、self.initialize_request,TestAPIView没有,调用APIView的initialize_request方法,构建drf的request对象

    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),#获取认证对象
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        ) 

5.1、self.get_authenticators(),TestAPIView没有,调用父类的APIView的get_authenticators

    def get_authenticators(self):
        return [auth() for auth in self.authentication_classes]

5.2、 self.authentication_classes : self=TestAPIView的实例对象

  • 如果TestAPIView中设置了authentication_classes 成员变量

    • class TestAPIView(APIView):
          authentication_classes=[MyJWTAuthentication]
          def get(self,request)
              return Respponse({'code':200,'msg':'测试通过'})
      
  • 如果TestAPIView没有设置,就去父类APIView中获取

    • class APIView(View):
          authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
      
      #这里就是去settings.py中获取配置
      REST_FRAMEWORK = {
          #1、全局认证
          'DEFAULT_AUTHENTICATION_CLASSES':['authen.authentication.MyJWTAuthentication'],
      }
      

5.3、获取到的就是[认证类(),]

5.4、新的request的初始化:drf的request对象,其实例变量authenticators=[认证类(),]

class Request:
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        self._request = request
        self.authenticators = authenticators or ()

6、self.initial(request,),TestAPIView中没有,找APIView的initial方法,

    def initial(self, request, *args, **kwargs):
        #认证、权限、限流
        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)

7、self.perform_authentication(request), TestAPIView中没有,找APIView的perform_authentication方法

    #request 是drf的request,调用request的user
    def perform_authentication(self, request):
        request.user

8、request是drf创建的request对象,调用request.user方法(此后,就是去找Request类了)

from rest_framework.request import Request

@property
def user(self):
    if not hasattr(self, '_user'):
        with wrap_attributeerrors():
        	self._authenticate()
    return self._user
  • 在实例化request对象时,初始化中没有_user的成员变量

  • 执行self._authenticate()方法,request的self._authenticate()方法

    •     #self=request
          def _authenticate(self):
              #去Request的authenticators 实例变量中获取认证类对象类别
              for authenticator in self.authenticators:
                  try:
                      #执行authenticate方法,返回元组,(user,token)
                      user_auth_tuple = authenticator.authenticate(self)
                  except exceptions.APIException:
                      self._not_authenticated()
                      raise
      			#认证通过
                  if user_auth_tuple is not None:
                      self._authenticator = authenticator
                      self.user, self.auth = user_auth_tuple
                      return
      		#认证不通过时,就是给request.user,request.auth 设置匿名用户了
              self._not_authenticated()
      

9、认证时,token没有异常:就进入下一步了

    def initial(self, request, *args, **kwargs):
        # Ensure that the incoming request is permitted
        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)

10、self.check_permissions(request) 方法,TestAPIView没有,找父类APIView的check_permissions方法

    def check_permissions(self, request):
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                #抛出异常错误
  • self.get_permissions(),TestAPIView没有,找APIView的get_permissions()

    •     def get_permissions(self):
              return [permission() for permission in self.permission_classes]
      
    • self.permission_classes

      • 如果TestAPIView中配置了permission_classes,优先使用视图函数中的
      • 如果TestAPIView没有配置,就使用APIView的
    • 结果:返回[权限对象1,权限对象2,…]

  • 循环遍历[权限对象1,权限对象2,…], 执行权限对象.has_permission方法

    • 要所有的权限对象都return True,都满足,才能进入到下一步
    • 只要其中一个不满足,就报错

11、假设所有权限对象都通过了

    def dispatch(self, request, *args, **kwargs):
        #处理url中的参数
        self.args = args
        self.kwargs = kwargs
        #构建drf的request对象
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            #认证、权限、限流的执行
            self.initial(request, *args, **kwargs)

            #通过反射来执行TestAPIView中的get、post等方法
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
			#视图函数执行结果
            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

12、使用反射,TestAPIView的get方法,执行后,获取返回值。

总结:
1、权限类是依赖于认证类的完成,没有设置认证的视图,就不应该设置权限类
2、权限类的流程,大致跟认证差不多的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/301471.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Weblogic安全漫谈(三)

本篇介绍coherence.jar中的漏洞利用链及后续绕过。 经历2015到2018的3年迭代后,Weblogic的黑名单逐渐完善,废掉CC反序列化更是釜底抽薪。另一方面也促使研究员去挖掘新组件新利用链,这篇介绍的就是testbnull在发现Spring写文件链后[1]&#…

spring boot支付宝沙箱环境测试支付功能

目录 一、安装支付宝支付demo 二、配置demo信息 三、配置回调地址和异步地址 四、内网穿透 (一)简介 (二)使用场景 (三)内网穿透的几个常用软件 (四)使用natapp 一、安装支付…

ckplayer如何设置键盘的方向左和方向右是快退或快进多少秒?

默认是20秒,那怎么按照自定义的配置呢? 打开文件:“.\ckplayer\js\ckplayer.js” 然后在下面的函数中修改就可以了: 下面的代码我已经修改为了按一次方向左键为快退3秒,按一次方向右键为快进5秒。 /** fastBack* 功能&…

第03章_运算符与流程控制

第03章_运算符与流程控制 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 本章专题脉络 1. 运算符(Operator) 运算符是一种特殊的符号,用以表示数据的运算、赋…

DevOps搭建(十五)-kubernetes部署项目详细步骤

1、k8s简介 k8s官网地址 https://kubernetes.io/zh-cn/docs/home/ 2、安装kuboard 详细步骤可参考官网 https://kuboard.cn/install/install-k8s.html 2.1、环境准备 至少 2 台 2核4G 的服务器。 选择v1.19,因为高版本的已经把docker给舍弃掉了。 https://k…

Vue3插件开发教程:步步指导如何编写Vue3插件

关注⬆️⬆️⬆️⬆️ 专栏后期更新更多前端内容 文章目录 Vue3 插件插件注册形式插件主要的场景使用插件Vue3 插件 插件 (Plugins) 是一种能为 Vue 添加全局功能的工具代码。 插件注册形式 一个插件可以是一个拥有 install() 方法的对象,也可以直接是一个安装函数本身。 i…

Transformer从菜鸟到新手(三)

引言 这是Transformer的第三篇文章,上篇文章中我们了解了多头注意力和位置编码,本文我们继续了解Transformer中剩下的其他组件。 下篇文章会介绍完整的训练过程。 层归一化 层归一化想要解决一个问题,这个问题在Batch Normalization的论文…

【JaveWeb教程】(1)Web前端基础:HTML+CSS入门不再难:一篇文章教你轻松搞定HTML与CSS!

目录 1. 前端开发介绍2. HTML & CSS2.1 HTML快速入门2.1.1 操作2.1.2 总结 2.2 开发工具2.3 基础标签 & 样式2.3.1 新浪新闻-标题实现2.3.1.1 标题排版2.3.1.1.1 分析2.3.1.1.2 标签2.3.1.1.2 实现 2.3.1.2 标题样式2.3.1.2.1 CSS引入方式2.3.1.2.2 颜色表示2.3.1.2.3 …

书生·浦语大模型趣味 Demo笔记及作业

文章目录 笔记作业基础作业:进阶作业: 笔记 书生浦语大模型InternLM-Chat-7B 智能对话 Demo:https://blog.csdn.net/m0_49289284/article/details/135412067书生浦语大模型Lagent 智能体工具调用 Demo:https://blog.csdn.net/m0_…

大模型日报-20240108

M(2)UGen:利用 LLM 理解和生成音乐 https://github.com/shansongliu/M2UGen M (2) UGen 模型是一种音乐理解和生成模型,能够从文本、图像、视频和音频中进行音乐问答和音乐生成,以及音乐编辑。该模型利用编码器,如用于音乐理解的…

代码随想录day60:贪心算法|84.柱状图中最大的矩形

84. Largest Rectangle in Histogram 进行优化,如果我们想获得left就给他left即可,我们只需要在求宽度的时候用到left,而没必要修改原数组。 所以给栈插入一个虚拟索引-1 思考过程: left应该为多少呢? 首先确定left是什么&#…

吴飞教授 人工智能 模型与算法 启发式搜索课件发散分析

一、文章介绍 本文是针对吴飞教授在MOOC课程 :《人工智能:模型与算法》 2.1节 启发式搜索的课前发散 在课程2.1节 启发式搜索章节中,吴飞教授以如何计算城市地图两点之间最短路径为例,重点讲授了贪婪最佳优先搜索和A*搜索算法&a…

Materialise Mimics各版本安装指南

Materialise Mimics下载链接 https://pan.baidu.com/s/1GYnAuXfbgk_n-OXLNSOt6w?pwd0531 1.鼠标右击【Materialise Mimics21】压缩包(win11及以上系统需先点击“显示更多选项”)【解压到 Materialise Mimics21】。 2.打开解压后的文件夹,鼠…

网页设计与制作web前端设计html+css+js成品。电脑网站制作代开发。vscodeDrea 【企业公司宣传网站(HTML静态网页项目实战)附源码】

网页设计与制作web前端设计htmlcssjs成品。电脑网站制作代开发。vscodeDrea 【企业公司宣传网站(HTML静态网页项目实战)附源码】 https://www.bilibili.com/video/BV1Hp4y1o7RY/?share_sourcecopy_web&vd_sourced43766e8ddfffd1f1a1165a3e72d7605

大学物理-实验篇——用拉伸法测定金属丝的杨氏(弹性)模量(胡克定律、杨氏模量、平面反射镜、三角函数、螺旋测微器)

目录 预备知识 力学:胡克定律(Hookes law) 材料力学:杨氏模量 光学:平面反射镜 数学:三角函数 螺旋测微器 实验目的 实验仪器 实验原理 1.拉伸法测杨氏弹性模量 2.光杠杆放大法测量微小伸长量 …

Mac M1 Parallels CentOS7.9 Install Parallels Tools

一、挂载parallels-tools安装包 mkdir /media/cdrom/ mount /dev/cdrom /media/cdrom/ mount: /dev/sr0 写保护,将以只读方式挂载二、GCC升级 yum install -y centos-release-scl yum install -y devtoolset-8-gcc*# 切换当前会话中gcc版本为8 scl enable devtool…

HarmonyOS应用开发学习笔记 UIAbility组件与UI的数据同步 EventHub、globalThis

1、 HarmoryOS Ability页面的生命周期 2、 Component自定义组件 3、HarmonyOS 应用开发学习笔记 ets组件生命周期 4、HarmonyOS 应用开发学习笔记 ets组件样式定义 Styles装饰器:定义组件重用样式 Extend装饰器:定义扩展组件样式 5、HarmonyOS 应用开发…

重磅!图扑软件获评国家级专精特新“小巨人”企业

2023 年 7 月,工业和信息化部审核并公布了第五批国家级专精特新“小巨人”企业,图扑软件成功入选,荣膺国家级专精特新“小巨人”企业称号。 此次荣获国家级专精特新“小巨人”企业称号,不仅是对图扑软件在可视化和数字孪生领域专业…

ARCGIS PRO SDK Geoprocessing

调用原型:Dim gpResult AS IGPResult await Geoprocessing.ExecuteToolAsync(调用工具名称, GPValue数组, environment, null, null, executeFlags) 一、调用工具名称:地理处理工具名称。如面转线:management.PolygonToLine,而非…

实例:NodeJS 操作 Kafka

本人是C#出身的程序员,c#很简单就能实现,有需要的可以加我私聊。但是就目前流行的开发语言,尤其是面向web方向应用的,我感觉就是Nodejs最简单了。下面介绍: 本文将会介绍在windows环境下启动Kafka,并通过n…