频率认证
shell环境
频率简介
为了控制用户对某个url请求的频率,比如,一分钟以内,只能访问三次
自定义频率类,自定义频率规则
1.在settings中配置 INSTALLED_APPS=['rest_framework']
2.settings中配置
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES':{
'luffy':'3/m'
#scope='lxx',表示一分钟访问三次
}
}
3.models.py
from django.db import models # Create your models here. class Book(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) publish_date = models.DateField(null=True) xx=models.IntegerField(choices=((0,'文学类'),(1,'情感类')),default=1,null=True) publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE,null=True) authors=models.ManyToManyField(to='Author') def __str__(self): return self.name def test(self): return 'xxx' class Author(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() class Publish(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() def __str__(self): return self.name
注意:数据迁移
4.urls.py
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'books/', views.Books.as_view()) ]
5.views.py
from django.shortcuts import render # Create your views here. from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.throttling import SimpleRateThrottle,BaseThrottle #第一步,写一个频率类,继承SimpleRateThrottle #重写get_cache_key, 返回self.get_ident(request) #一定要记住配置一个scope字符串 #第二步:在settings中配置 #频率的一个类 class Throttle(SimpleRateThrottle): scope='lxx' def get_cache_key(self, request, view): return self.get_ident(request) class Books(APIView): throttle_classes = [] def get(self, request): return Response('')
编写自定义的类
from django.shortcuts import render # Create your views here. from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.throttling import SimpleRateThrottle,BaseThrottle #第一步,写一个频率类,继承SimpleRateThrottle #重写get_cache_key, 返回self.get_ident(request) #一定要记住配置一个scope字符串 #第二步:在settings中配置 #频率的一个类 class Throttle(SimpleRateThrottle): scope='lxx' def get_cache_key(self, request, view): return self.get_ident(request) #自定义频率类 class MyThrottle(BaseThrottle): VISIT_RECORD = {} def __init__(self): self.history = None def allow_request(self, request, view): #自定义控制每分钟访问多少次,允许访问返回true,不允许访问返回false # (1)取出访问者ip # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走 # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间, # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过 # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败 # (1)取出访问者ip # print(request.META) ip = request.META.get('REMOTE_ADDR') import time ctime = time.time() # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问 if ip not in self.VISIT_RECORD: self.VISIT_RECORD[ip] = [ctime, ] return True self.history = self.VISIT_RECORD.get(ip) # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间, while self.history and ctime - self.history[-1] > 60: self.history.pop() # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过 # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败 if len(self.history) < 3: self.history.insert(0, ctime) return True else: return False def wait(self): import time ctime = time.time() return 60 - (ctime - self.history[-1]) class Books(APIView): throttle_classes = [] def get(self, request): return Response('')
自定义的逻辑
#(1)取出访问者ip # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走 # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间, # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过 # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
以下是源码(跟我们自定义的逻辑一样,也是要重写allow_request方法)分析:😁
-SimpleRateThrottle源码🎇
点击SimpleRateThrottle进入到类中,找到allow_request方法
补充:这个访问者ip是存放入缓存当中,而在自定义的逻辑中的是保存在字典中,这里的reqeust.META.get('REMOTE_ADDR')只是暂时的获取到ip,后面要改为
self.get_ident(request)
然后在缓存里根据ip地址取出时间列表
获取当前时间
判断当前时间是否为空,并且取出最后一个值是否大于我配置的时间,当前时间减去我配置时间进行做比较,如果是就把最后的时间pop,再判断长度是否大于我配置的3,大于3不能访问,小于3可以访问
以上总结:不需要写allow_reqeust的方法的,只需要重写获取ip的get_cache_key的方法
在__init__返回rate,这个rate就是3/m
然后把3/m传入parse_rate中
再读parse_rate,通过斜杆切分再解压,period[0]字符串取第0个值,如果period=m,现在duration=60,返回3 和60,这些值就可以动态获取
SimpleRateThrottle中的父类中有BaseThrottle才有,返回访问者的ip
返回什么值就以什么来过滤,返回ip就以ip做过滤,返回用户的id就以用户的id做过滤