Django-Rest frameworw用户访问次数/频率限制

一、示例展示

=============******=============

            1、BaseThrottle原类

            2、基于用户IP限制访问频率 (了解)

            3、基于用户IP显示访问频率(利于Django缓存) # 经常使用

            4、匿名时用IP限制+登录时用Token限制

=============******=============

全局使用:

in settings.py

  1.  
    REST_FRAMEWORK = {
  2.  
    'DEFAULT_THROTTLE_CLASSES': [
  3.  
    'api.utils.throttles.throttles.LuffyAnonRateThrottle',
  4.  
    'api.utils.throttles.throttles.LuffyUserRateThrottle',
  5.  
    ],
  6.  
    'DEFAULT_THROTTLE_RATES': {
  7.  
    'anon': '10/day',
  8.  
    'user': '10/day',
  9.  
    'luffy_anon': '10/m',
  10.  
    'luffy_user': '20/m',
  11.  
    },
  12.  
    }

 

1、BaseThrottle原类

  1.  
    class BaseThrottle(object):
  2.  
    """
  3.  
    Rate throttling of requests.
  4.  
    """
  5.  
     
  6.  
    def allow_request(self, request, view): #判断是否允许请求,来访问
  7.  
    """
  8.  
    Return `True` if the request should be allowed, `False` otherwise.
  9.  
    """
  10.  
    raise NotImplementedError('.allow_request() must be overridden')
  11.  
     
  12.  
    def get_ident(self, request): # 获取请求的IP,
  13.  
    xff = request.META.get('HTTP_X_FORWARDED_FOR')
  14.  
    remote_addr = request.META.get('REMOTE_ADDR')
  15.  
    num_proxies = api_settings.NUM_PROXIES
  16.  
     
  17.  
    if num_proxies is not None:
  18.  
    if num_proxies == 0 or xff is None:
  19.  
    return remote_addr
  20.  
    addrs = xff.split(',')
  21.  
    client_addr = addrs[-min(num_proxies, len(addrs))]
  22.  
    return client_addr.strip()
  23.  
     
  24.  
    return ''.join(xff.split()) if xff else remote_addr
  25.  
     
  26.  
    def wait(self): # 等待时间设置
  27.  
    """
  28.  
    Optionally, return a recommended number of seconds to wait before
  29.  
    the next request.
  30.  
    """
  31.  
    return None

2、基于用户IP限制访问频率 (了解)

  1.  
    in url.py
  2.  
    from django.conf.urls import url, include
  3.  
    from web.views import TestView
  4.  
     
  5.  
    urlpatterns = [
  6.  
    url(r'^test/', TestView.as_view()),
  7.  
    ]
  8.  
    in views.py
  9.  
    #!/usr/bin/env python
  10.  
    # -*- coding:utf-8 -*-
  11.  
    import time
  12.  
    from rest_framework.views import APIView
  13.  
    from rest_framework.response import Response
  14.  
     
  15.  
    from rest_framework import exceptions
  16.  
    from rest_framework.throttling import BaseThrottle
  17.  
    from rest_framework.settings import api_settings
  18.  
     
  19.  
    # 保存访问记录
  20.  
    RECORD = {
  21.  
    '用户IP': [12312139, 12312135, 12312133, ]
  22.  
    }
  23.  
     
  24.  
     
  25.  
    class TestThrottle(BaseThrottle):
  26.  
    '''仿照SimpleRateThrottle这个类,做简单化处理,看懂后在看SimpleRateThrottle就很简单了'''
  27.  
    ctime = time.time
  28.  
     
  29.  
    def get_ident(self, request):
  30.  
    """
  31.  
    根据用户IP和代理IP,当做请求者的唯一IP
  32.  
    """
  33.  
    xff = request.META.get('HTTP_X_FORWARDED_FOR')
  34.  
    remote_addr = request.META.get('REMOTE_ADDR')
  35.  
    num_proxies = api_settings.NUM_PROXIES
  36.  
     
  37.  
    if num_proxies is not None:
  38.  
    if num_proxies == 0 or xff is None:
  39.  
    return remote_addr
  40.  
    addrs = xff.split(',')
  41.  
    client_addr = addrs[-min(num_proxies, len(addrs))]
  42.  
    return client_addr.strip()
  43.  
     
  44.  
    return ''.join(xff.split()) if xff else remote_addr
  45.  
     
  46.  
    def allow_request(self, request, view):
  47.  
    """
  48.  
    是否仍然在允许范围内
  49.  
    :return: True,表示可以通过;False表示已超过限制,不允许访问
  50.  
    """
  51.  
    # 获取用户唯一标识(如:IP)
  52.  
     
  53.  
    # 允许一分钟访问10次
  54.  
    num_request = 10
  55.  
    time_request = 60
  56.  
     
  57.  
    now = self.ctime()
  58.  
    ident = self.get_ident(request)
  59.  
    self.ident = ident
  60.  
    if ident not in RECORD:
  61.  
    RECORD[ident] = [now, ]
  62.  
    return True
  63.  
    history = RECORD[ident]
  64.  
    while history and history[-1] <= now - time_request:
  65.  
    history.pop()
  66.  
    if len(history) < num_request:
  67.  
    history.insert(0, now)
  68.  
    return True
  69.  
     
  70.  
    def wait(self):
  71.  
    """
  72.  
    多少秒后可以允许继续访问
  73.  
    """
  74.  
    last_time = RECORD[self.ident][0]
  75.  
    now = self.ctime()
  76.  
    return int(60 + last_time - now)
  77.  
     
  78.  
     
  79.  
    class TestView(APIView):
  80.  
    throttle_classes = [TestThrottle, ]
  81.  
     
  82.  
    def get(self, request, *args, **kwargs):
  83.  
    # self.dispatch
  84.  
    print(request.user)
  85.  
    print(request.auth)
  86.  
    return Response('GET请求,响应内容')
  87.  
     
  88.  
    def post(self, request, *args, **kwargs):
  89.  
    return Response('POST请求,响应内容')
  90.  
     
  91.  
    def put(self, request, *args, **kwargs):
  92.  
    return Response('PUT请求,响应内容')
  93.  
     
  94.  
    def throttled(self, request, wait):
  95.  
    """
  96.  
    访问次数被限制时,定制错误信息
  97.  
    """
  98.  
     
  99.  
    class Throttled(exceptions.Throttled):
  100.  
    default_detail = '请求被限制.'
  101.  
    extra_detail_singular = '请 {wait} 秒之后再重试.'
  102.  
    extra_detail_plural = '请 {wait} 秒之后再重试.'
  103.  
     
  104.  
    raise Throttled(wait)

3、基于用户IP显示访问频率(利于Django缓存) # 经常使用

  1.  
    in settings.py
  2.  
    REST_FRAMEWORK = {
  3.  
    'DEFAULT_THROTTLE_RATES': {
  4.  
    'test_scope': '10/m', # s 秒 h 小时 d 天 m 分钟 等等 源码通过/切割,判断右边首位是什么来判断时间单位
  5.  
    },
  6.  
    }
  7.  
     
  8.  
    in url.py
  9.  
    from django.conf.urls import url, include
  10.  
    from web.views import TestView
  11.  
     
  12.  
    urlpatterns = [
  13.  
    url(r'^test/', TestView.as_view()),
  14.  
    ]
  15.  
     
  16.  
    in views.py
  17.  
    #!/usr/bin/env python
  18.  
    # -*- coding:utf-8 -*-
  19.  
    from rest_framework.views import APIView
  20.  
    from rest_framework.response import Response
  21.  
     
  22.  
    from rest_framework import exceptions
  23.  
    from rest_framework.throttling import SimpleRateThrottle
  24.  
     
  25.  
     
  26.  
    class TestThrottle(SimpleRateThrottle):
  27.  
     
  28.  
    scope = 'test_scope' # 显示频率的Key,在配置文件里需要有个跟这个同名
  29.  
     
  30.  
    def get_cache_key(self, request, view):
  31.  
    return self.get_ident(request) # 获取请求IP
  32.  
     
  33.  
     
  34.  
    class TestView(APIView):
  35.  
    throttle_classes = [TestThrottle, ]
  36.  
     
  37.  
    def get(self, request, *args, **kwargs):
  38.  
    # self.dispatch
  39.  
    print(request.user)
  40.  
    print(request.auth)
  41.  
    return Response('GET请求,响应内容')
  42.  
     
  43.  
    def post(self, request, *args, **kwargs):
  44.  
    return Response('POST请求,响应内容')
  45.  
     
  46.  
    def put(self, request, *args, **kwargs):
  47.  
    return Response('PUT请求,响应内容')
  48.  
     
  49.  
    def throttled(self, request, wait):
  50.  
    """
  51.  
    访问次数被限制时,定制错误信息
  52.  
    """
  53.  
     
  54.  
    class Throttled(exceptions.Throttled):
  55.  
    default_detail = '请求被限制.'
  56.  
    extra_detail_singular = '请 {wait} 秒之后再重试.'
  57.  
    extra_detail_plural = '请 {wait} 秒之后再重试.'
  58.  
     
  59.  
    raise Throttled(wait)
4、匿名时用IP限制+登录时用Token限制
  1.  
    in settings.py
  2.  
    REST_FRAMEWORK = {
  3.  
    'UNAUTHENTICATED_USER': None,
  4.  
    'UNAUTHENTICATED_TOKEN': None,
  5.  
    'DEFAULT_THROTTLE_RATES': {
  6.  
    'luffy_anon': '10/m',
  7.  
    'luffy_user': '20/m',
  8.  
    },
  9.  
    }
  10.  
    in url.py
  11.  
    from django.conf.urls import url, include
  12.  
    from web.views.s3_throttling import TestView
  13.  
     
  14.  
    urlpatterns = [
  15.  
    url(r'^test/', TestView.as_view()),
  16.  
    ]
  17.  
    in views.py
  18.  
    #!/usr/bin/env python
  19.  
    # -*- coding:utf-8 -*-
  20.  
    from rest_framework.views import APIView
  21.  
    from rest_framework.response import Response
  22.  
     
  23.  
    from rest_framework.throttling import SimpleRateThrottle
  24.  
     
  25.  
     
  26.  
    class LuffyAnonRateThrottle(SimpleRateThrottle):
  27.  
    """
  28.  
    匿名用户,根据IP进行限制
  29.  
    """
  30.  
    scope = "luffy_anon"
  31.  
     
  32.  
    def get_cache_key(self, request, view):
  33.  
    # 用户已登录,则跳过 匿名频率限制
  34.  
    if request.user:
  35.  
    return None
  36.  
     
  37.  
    return self.cache_format % {
  38.  
    'scope': self.scope,
  39.  
    'ident': self.get_ident(request)
  40.  
    }
  41.  
     
  42.  
     
  43.  
    class LuffyUserRateThrottle(SimpleRateThrottle):
  44.  
    """
  45.  
    登录用户,根据用户token限制
  46.  
    """
  47.  
    scope = "luffy_user"
  48.  
     
  49.  
    def get_ident(self, request):
  50.  
    """
  51.  
    认证成功时:request.user是用户对象;request.auth是token对象
  52.  
    :param request:
  53.  
    :return:
  54.  
    """
  55.  
    # return request.auth.token
  56.  
    return "user_token"
  57.  
     
  58.  
    def get_cache_key(self, request, view):
  59.  
    """
  60.  
    获取缓存key
  61.  
    :param request:
  62.  
    :param view:
  63.  
    :return:
  64.  
    """
  65.  
    # 未登录用户,则跳过 Token限制
  66.  
    if not request.user:
  67.  
    return None
  68.  
     
  69.  
    return self.cache_format % {
  70.  
    'scope': self.scope,
  71.  
    'ident': self.get_ident(request)
  72.  
    }
  73.  
     
  74.  
     
  75.  
    class TestView(APIView):
  76.  
    throttle_classes = [LuffyUserRateThrottle, LuffyAnonRateThrottle, ]
  77.  
     
  78.  
    def get(self, request, *args, **kwargs):
  79.  
    # self.dispatch
  80.  
    print(request.user)
  81.  
    print(request.auth)
  82.  
    return Response('GET请求,响应内容')
  83.  
     
  84.  
    def post(self, request, *args, **kwargs):
  85.  
    return Response('POST请求,响应内容')
  86.  
     
  87.  
    def put(self, request, *args, **kwargs):
  88.  
    return Response('PUT请求,响应内容')
  89.  

posted @ 2019-03-01 16:33  老虎死了还有狼  阅读(67)  评论(0)    收藏  举报