首页 > 编程语言 >权限类、频率类、鸭子类型、源码分析(认证类源码、权限类源码)

权限类、频率类、鸭子类型、源码分析(认证类源码、权限类源码)

时间:2022-10-09 21:33:46浏览次数:53  
标签:permission self request 源码 user 权限 鸭子

目录

权限类

一、认证

  • 校验用户是否登录,登录认证

  • 用户登录后,某个接口限定只有超级用户才能访问,普通用户不能访问

二、需求

  • 出版社所有的接口,必须先登录,而且是超级管理员才能访问

三、使用步骤

  • 第一步:写一个类,继承BasePermission
  • 第二步:重写has_permission方法
  • 第三步:在方法中校验用户是否有权限(request.user就是当前登录用户)
  • 第四步:有权限,返回True;没有权限,返回False
  • 第五步:self.message 是给前端的提示信息
  • 第六步:局部使用;全局使用,局部禁用
from rest_framework.permissions import BasePermission


class UserTypePermission(BasePermission):
    def has_permission(self, request, view):
        # 只有超级管理员有权限
        if request.user.user_type == 1:
            return True  # 有权限
        else:
            # self.message = '普通用户和游客用户都没有权限' # 返回给前端的提示
            # 使用choice后,user.user_type拿到的数字类型,想变成对应的字符串user.get_user_type_display()
            self.message = '您是:%s,您没有权限' % request.user.get_user_type_display()
            return False  # 没有权限

频率类

一、应用

短时间内大量的访问会导致程序崩溃

无论是否登录,是否有权限都要限制访问的频率

eg:一分钟访问限最多三次

二、使用步骤

  • 第一步:写一个类,继承SimpleRateThrottle

  • 第二步:重写get_cache_key,返回唯一的字符串,会以这个字符串做频率限制

  • 第三步:写一个类属性 scope='随意写',必须要跟配置文件对应

  • 第四步:配置文件中写

    'DEFAULT_THROTTLE_RATES': {'frequency': '5/m'},
    
  • 第五步:局部使用;全局使用,局部禁用

from rest_framework.throttling import SimpleRateThrottle, BaseThrottle


class Throttle(SimpleRateThrottle):
    # 类属性,这个属性可以随意命名,但是要和配置文件对应
    scope = 'frequency'
    def get_cache_key(self, request, view):
        # 返回什么,就以什么限制频率
        # 可以通过用户id 或 IP地址
        return request.META.get('REMOTE_ADDR')

# 配置文件中
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_RATES': {'frequency': '5/m'},
}

源码分析

'''
写个认证类,重写某个方法,配置在实体类上,就有了认证
--->
只要加了认证类,在视图类的方法中的request.user就是当前登录用户
--->
猜测:认证类的执行,是在视图类的方法之前执行的
'''

# 源码分析
	- 之前读APIView的执行流程:
    	包装了新的request,
    	执行了三大认证,
    	执行视图类的方法,
    	处理了全局异常
    
   - 入口:APIView的dispatch
	- APIView的dispatch里的异常捕获里
    	self.initial(request, *args, **kwargs)
	- APIView的initial里有三句话,分别是:认证,权限,频率
    	self.perform_authentication(request)  # 认证
    	self.check_permissions(request)  # 权限
    	self.check_throttles(request)  # 频率

一、认证源码分析

  	- 读认证类的源码
		 def perform_authentication(self, request):
        request.user	# 新的request
      
   - request是新的request --> Request类中找'user'属性(方法包装成了属性)
	- 到Request类中找:220行
		def user(self):
        if not hasattr(self, '_user'):  # Request类的对象中反射_user
            with wrap_attributeerrors():
                self._authenticate()  # 第一次一定会走这个代码
        return self._user
   - Request的self._authenticate():373行
		def _authenticate(self):
        for authenticator in self.authenticators:  # 配置在视图类中所有的认证类的对象
            try:
                # user_auth_tuple:(user_token,token)
                user_auth_tuple = authenticator.authenticate(self)  # 调用认证类对象的authenticator
                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
								# 认证类可以配置多个,但是一旦返回了两个值,后续的不会再执行
                    self._not_authenticated()

'''
总结:
	认证类:要重写authenticator方法
	认证通过:返回两个值或None
	认证不通过:抛认证不通过抛AuthenticationFailed(继承了APIException)异常
'''                    

二、权限源码分析

- 最简单的权限执行流程:APIView的check_permissions(),325行
    def check_permissions(self, request):
        for permission in self.get_permissions():
        # permission是配置在视图类中权限类的对象,对象调用他的绑定方法has_permission
        # 对象调用自己的绑定方法会把自己传入(self, request, view)=(权限类的对象,request,视图类的对象)
            if not permission.has_permission(request, self):  # 这个self是APIView的对象,也就是传入的view
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )
- APIView的self.get_permissions(),274行
	def get_permissions(self):
		return [permission() for permission in self.permission_classes]
   - self.permission_classes 就是在视图类中配的'权限类'的列表
	- 所以这个get_permissions返回的是:在视图类中配的'权限类的对象'列表[UserTypePermission(),]
    
'''
总结:
	- 为什么要写一个类,重写has_permission方法,有三个参数
		对象调用自己的绑定方法会把自己传入,permission调用has_permission,
		第三个参数view就是传给if not permission.has_permission(request, self) 的 self
		
	- 为什么一定要return True或False 
		要用来做if判断
		
	- messgage可以做什么用
		给前端的提示
'''

三、频率类源码

- APIView的check_throttles:352行
    def check_throttles(self, request):
        throttle_durations = []
        for throttle in self.get_throttles():
            if not throttle.allow_request(request, self):
                throttle_durations.append(throttle.wait())

        if throttle_durations:
            durations = [
                duration for duration in throttle_durations
                if duration is not None
            ]

            duration = max(durations, default=None)
            self.throttled(request, duration)
            
'''
总结:
	要写频率类,必须重写allow_request方法
	没有到频率的限制:返回True
	到频率限制:返回False
'''

鸭子类型

一、通俗化的解释

走路像鸭子,说话像鸭子,它就是鸭子

二、详细说明

在Python中:

​ 指的是面向对象中,子类不需要显示的继承某个类,只要有某个类中的方法和属性,那就属于这个类

在其他的语言中:

​ 必须要继承某个类,才属于这个类

假设有个鸭子类Duck类,有两个方法:run,speak

1.其他语言中:
    # 假设又有一个普通鸭子类:PDuck
       如果它也是鸭子,它需要继承Duck类,只要继承了鸭子类,什么都不需要写,普通鸭子类的对象就是鸭子这种类型;
       如果不继承,普通鸭子类的对象就不是鸭子这种类型

    # 假设又有一个唐老鸭子类:TDuck
        如果它也是鸭子,它需要继承Duck类,只要继承了鸭子类,什么都不需要写,唐老鸭子类的对象就是鸭子这种类型;
       如果不继承,唐老鸭子类的对象就不是鸭子这种类型
    
2.在python中:
	只要PDuck中有run和speak方法,PDuck就是属于Duck这个类
   # 缺陷:
		如果使用python鸭子类型的写法,如果方法名写错了,就不属于鸭子类,容易出问题
   # 解决缺陷:
		- 方式一:
			abc模块装饰后,必须重写方法,不重写就报错
		- 方法二:
        drf源码中使用的:父类中写这个方法,但没有具体实现,直接抛异常

注意

django中的配置文件不要最易导入,可能会出错

django的运行是在加载完配置文件之后才运行
在配置文件中导入模块,会先执行模块,而这个模块中导入的其他模块必需要django运行才能使用

作业

class BThrottle(BaseThrottle):
    ask_dict = {}

    def allow_request(self, request, view):
        # 自定义逻辑{ip:[时间1,时间2]}
        # 1.取出访问者IP
        # 2.判断当前IP是否在访问字典内,没有:添加,返回True,表示第一次访问;有:继续往下走
        # 3.循环判断当前IP的列表,有值,并且当前时间减去列表最后一个时间大于60s,pop这种数据,这样列表中只有60s以内的访问时间
        # 4.判断,当列表小于5,说明一分钟内访问不足5次,把当前时间插入到列表第一个位置,返回True,顺利通过
        # 5.当列表大于等于5,说明一分钟内访问超过五次,返回False验证失败
        # user_ip = request.META.get('REMOTE_ADDR')
        user_id = request.user.id
        time1 = time.time()
        if user_id not in self.ask_dict:
            self.ask_dict[user_id] = [time1, ]
            return True
        else:
            last_time = self.ask_dict.get(user_id)
            if time1 - last_time[0] > 60:
                self.ask_dict[user_id] = [time1, ]
                return True
            else:
                count = len(last_time)
                if count >= 5:
                    return False
                else:
                    last_time.insert(0, time1)
                    return True

标签:permission,self,request,源码,user,权限,鸭子
From: https://www.cnblogs.com/Zhang614/p/16773775.html

相关文章

  • drf三大认证之权限源码解析
    1.认证,频率,权限的源码解读入口就是APIView源码的dispatch方法的三大认证,全局异常处理self.initial(request,*args,**kwargs)2.查看APIView的initial里面的三句代......
  • Go Mutex 源码详解
    前言在上一篇文章中,我们一起学习了如何使用​​Go​​​中的互斥锁​​Mutex​​​,那么本篇文章,我们就一起来探究下​​Mutex​​底层是如何实现的,知其然,更要知其所以......
  • 推荐一个今天误入的 源码学习网站
    今天想查看一下 spring data JPA 的源码,然后看到一个不错的源码学习网站。 链接地址:​​http://www.iocoder.cn/Spring-Data-JPA/good-collection/​​......
  • drf三大认证(认证,权限,频率)及其源码分析
    drf三大认证之认证drf三大认证之权限drf三大认证之频率drf三大认证之认证源码分析drf三大认证之权限源码分析鸭子类型drf三大认证之认证  访问接......
  • drf -三大权限认证例子
    三大权限认证测试例子代码models.pyfromdjango.dbimportmodels#Createyourmodelshere.classBook(models.Model):name=models.CharField(max_length=3......
  • drf之权限类与频率类
    一、权限类#权限就是我们在登入之后我们在访问这个接口的时候有没有访问的权限#eg:现在我们把用户等级分为两个等级,一个为vip用户,一个为普通用户然......
  • 基于SSM+Vue校园勤工助学网站Java大学生勤工俭学管理系统(源码调试+讲解+文档)
    ......
  • 权限类,频率类的使用及源码分析
    权限类的使用使用场景:用户登录后,某个接口只有管理员才能访问,普通用户不能访问例:出版社的所有接口必须登录并且士管理员才能访问使用步骤:一.写一个类,继承BasePermi......
  • 从SpringBoot启动,阅读源码设计
    服务启动堪称Spring源码设计的答案;一、背景说明初学SpringBoot框架时,第一次启动服务,直呼什么鬼?只需要简单的几步配置,几个核心的注解,就可以快速实现工程的搭建和运行;虽......
  • HashMap 源码,看我这篇就够了
    HashMap源码,看我这篇就够了HashMap源码深度剖析*HashMap底层数据结构(为什么引入红黑树、存储数据的过程、哈希碰撞相关问题)*HashMap成员变量(初始化容量是多少、......