Django Rest Framework --用户访问频率限制

自定义访问频率控制类结构

views.py

from rest_framework.throttling import BaseThrottle
import time
# 节流
visit_dict={}

class Visitthrottle(BaseThrottle):
    #通过IP做唯一标识符
    #问题:非登陆用户一分钟内只允许访问3次
    def __init__(self):
        self.history=None

    def allow_request(self,request, view):
        #获取IP地址
        remote_addr = self.get_ident(request)
        ctime=time.time()
        if remote_addr not in visit_dict:
            visit_dict[remote_addr]=[ctime,]
            return True
        self.history = visit_dict.get(remote_addr)
        while self.history and self.history[-1] <ctime - 60:
            self.history.pop()
        if len(self.history)<3:
            self.history.insert(0,ctime)
            return True

    def wait(self):
        ctime=time.time()
        return 60-(ctime-self.history[-1])


class TestThrottle(APIView):
     throttle_classes  =  [VisitThrottle,]
     
     def  get( self , request,  * args,  * * kwargs):
         pass
         '''
         等等一系列的视图功能方法
         '''

实现原理分析:

  • 需要使用用户IP地址作为唯一标识符,如果使用用户登陆账号作为唯一标识符,一个用户可能拥有多个账号,则达不到节流的目的,但使用IP地址也不是说一定不能改变,但相比于登陆账号,使用IP地址更能达到节流的作用。
  •  以IP地址作为KEY键,多个访问时间形参列表作为value存入字典中,用户每次访问读取字典,判断最后一次访问时间与这次访问时间相差时间,相差时间大于60秒,删除时间列表中最后元素,然后判断列表长度是否小于3,如果小于3,表示一分钟内未访问3次,允许继续访问。
  • 如果不允许访问,会执行wait函数,返回需要等待时间。
  • 但是在项目开发中不使用自定义节流类,是因为drf中已经实现了节流方法。内置接口代码基本结构,内置节流类的实现原理与自定义节流类原理相同。

内置节流类结构

settings.py:

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES':['api.utils.mythrottle.UserThrottle',]
    'DEFAULT_THROTTLE_RATES': {
        '未认证用户': '10/m',
        '已认证用户': '100/h',
    },
}

mythrottle.py:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import exceptions
from rest_framework.throttling import SimpleRateThrottle
 
 
class VisitThrottle(SimpleRateThrottle):
    scope = "未认证用户"
 
    def get_cache_key(self, request, view):
        return  self.get_ident(request)
       
 
class UserThrottle(SimpleRateThrottle):
    scope = "已认证用户"
 
    def get_cache_key(self, request, view):
        return  request.user  # 认证通过后,认证方法authenticate的返回值之一<br><br>


class TestThrottle(APIView):<br>  # 这样设置后,节流功能就会使用VisitThrottle类,而不会使用UserThrottle类
    throttle_classes = [VisitThrottle,]
     
    def get(self, request, *args, **kwargs):
        pass
        '''
        等等一系列的视图功能方法
        '''

  这里使用的节流类是继承了SimplePateThrottle类,而这个类利用了django内置的缓存来存储访问记录。通过全局节流设置,所有的视图类默认是使用UserThrottle类进行节流,如果不想使用默认的类就自定义给throttle_classes属性变量赋值,如:“throttle_classes = [VisitThrottle,]”。看到内置节流类的使用,可能一脸懵逼,下面进行源码分析。

源码分析

与之前认证权限控制的源码分析方法一致,先进入函数入口dispatch方法,封装完新的request对象后,进入initialize_request方法,我们会发现还有一个函数调用我们没有分析,所以这就是我们的节流函数。

1.为什么会使用scope属性变量,有什么用?

进入check_throttles函数,是否觉得很熟悉?没错在get_throttles方法中肯定也是一个列表生产式,返回一个有节流类实例组成的列表。

  

 在列表生成式中,先对内置类SimplePateThrottle进行实例化,在实例化中去拿到scope的值,并且根据值作为key值去配置文件中拿到对应value值。

 

猜你喜欢

转载自www.cnblogs.com/kxsph/p/10572147.html