Django REST框架:每用户限制

时间:2015-12-30 23:11:03

标签: django django-rest-framework throttling

我的用户需要非常高的节流量,因此他们可以使用很多系统。是否有一种简单的方法可以比其他用户提供更高的节流量?

我环顾四周但却找不到任何东西。

3 个答案:

答案 0 :(得分:8)

通过扩展UserRateThrottle并将特殊用户添加到我的设置文件中,我想出了一种方法。

这个类只是覆盖了allow_request方法,添加了一些特殊的逻辑来查看OVERRIDE_THROTTLE_RATES变量中是否列出了用户名:

class ExceptionalUserRateThrottle(UserRateThrottle):
    def allow_request(self, request, view):
        """
        Give special access to a few special accounts.

        Mirrors code in super class with minor tweaks.
        """
        if self.rate is None:
            return True

        self.key = self.get_cache_key(request, view)
        if self.key is None:
            return True

        self.history = self.cache.get(self.key, [])
        self.now = self.timer()

        # Adjust if user has special privileges.
        override_rate = settings.REST_FRAMEWORK['OVERRIDE_THROTTLE_RATES'].get(
            request.user.username,
            None,
        )
        if override_rate is not None:
            self.num_requests, self.duration = self.parse_rate(override_rate)

        # Drop any requests from the history which have now passed the
        # throttle duration
        while self.history and self.history[-1] <= self.now - self.duration:
            self.history.pop()
        if len(self.history) >= self.num_requests:
            return self.throttle_failure()
        return self.throttle_success()

要使用此功能,只需将DEFAULT_THROTTLE_CLASS设置为此类,然后将一些特殊用户放入OVERRIDE_THROTTLE_RATES,如下所示:

'DEFAULT_THROTTLE_CLASSES': (
    'rest_framework.throttling.AnonRateThrottle',
    'cl.api.utils.ExceptionalUserRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
    'anon': '100/day',
    'user': '1000/hour',
},
'OVERRIDE_THROTTLE_RATES': {
    'scout': '10000/hour',
    'scout_test': '10000/hour',
},

答案 1 :(得分:2)

我知道这是一个很老的话题,被接受的答案也对我有帮助。我想展示如何使用多个用户速率调节器,在这种情况下,为根用户提供更多的调节器

from rest_framework.settings import api_settings
from django.core.exceptions import ImproperlyConfigured

class RootRateThrottle(UserRateThrottle):
    """
    Limits the rate of API calls that may be made by a given user.
    The user id will be used as a unique cache key if the user is
    authenticated.  For anonymous requests, the IP address of the request will
    be used.
    """

    def get_cache_key(self, request, view):
        if request.user.is_authenticated:
            ident = request.user.pk
        else:
            ident = self.get_ident(request)

        self.rate = self.get_rate(request)
        logger.debug(
            "Throttling rate for %s: %s", request.user, self.rate
        )

        self.num_requests, self.duration = self.parse_rate(self.rate)
        return self.cache_format % {
            'scope': self.scope,
            'ident': ident
        }

    def get_rate(self, request=None):
        """
        Determine the string representation of the allowed request rate.
        """
        if not getattr(self, 'scope', None):
            msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
                   self.__class__.__name__)
            raise ImproperlyConfigured(msg)

        if request and request.user.is_superuser:
            throttle_rates = settings.REST_FRAMEWORK["ROOT_THROTTLE_RATES"]
        else:
            throttle_rates = api_settings.DEFAULT_THROTTLE_RATES
        try:
            return throttle_rates[self.scope]
        except KeyError:
            msg = "No default throttle rate set for '%s' scope" % self.scope
            raise ImproperlyConfigured(msg)

class ByMinuteRateThrottle(RootRateThrottle):
    scope = 'minute'


class ByHourRateThrottle(RootRateThrottle):
    scope = 'hour'


class ByDayRateThrottle(RootRateThrottle):
    scope = 'day'

设置部分看起来像这样

'DEFAULT_THROTTLE_CLASSES': [
    'threedi_api.throttling.ByMinuteRateThrottle',
    'threedi_api.throttling.ByHourRateThrottle',
    'threedi_api.throttling.ByDayRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
    'minute': '100/min',
    'hour': '1000/hour',
    'day': '5000/day',
},
'ROOT_THROTTLE_RATES': {
    'minute': '200/min',
    'hour': '2000/hour',
    'day': '10000/day',
},

答案 2 :(得分:1)

我在定制的Django REST Throttling之后找到了解决方案,

在3次登录尝试后阻止特定用户(在我的应用程序中阻止user_id)。在匿名用户登录6次后阻止IP地址。

prevent.py: -

#!/usr/bin/python

from collections import Counter

from rest_framework.throttling import SimpleRateThrottle
from django.contrib.auth.models import User


class UserLoginRateThrottle(SimpleRateThrottle):
    scope = 'loginAttempts'

    def get_cache_key(self, request, view):
        user = User.objects.filter(username=request.data.get('username'))
        ident = user[0].pk if user else self.get_ident(request)

        return self.cache_format % {
            'scope': self.scope,
            'ident': ident
        }

    def allow_request(self, request, view):
        """
        Implement the check to see if the request should be throttled.
        On success calls `throttle_success`.
        On failure calls `throttle_failure`.
        """
        if self.rate is None:
            return True

        self.key = self.get_cache_key(request, view)
        if self.key is None:
            return True

        self.history = self.cache.get(self.key, [])
        self.now = self.timer()

        while self.history and self.history[-1] <= self.now - self.duration:
            self.history.pop()

        if len(self.history) >= self.num_requests:
            return self.throttle_failure()

        if len(self.history) >= 3:
            data = Counter(self.history)
            for key, value in data.items():
                if value == 2:
                    return self.throttle_failure()
        return self.throttle_success(request)

    def throttle_success(self, request):
        """
        Inserts the current request's timestamp along with the key
        into the cache.
        """
        user = User.objects.filter(username=request.data.get('username'))
        if user:
            self.history.insert(0, user[0].id)
        self.history.insert(0, self.now)
        self.cache.set(self.key, self.history, self.duration)
        return True

Views.py: -

from .prevent import UserLoginRateThrottle
   ....
   ....
   ....
   class ObtainAuthToken(auth_views.ObtainAuthToken):
       throttle_classes = (UserLoginRateThrottle,)/use this method here your login view

       def post(self, request, *args, **kwargs):
           ....
           ....

Settings.py: -

Django的其余框架

REST_FRAMEWORK = {
    ...
    ...
    ...
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.UserRateThrottle',

    ),
    'DEFAULT_THROTTLE_RATES': {
        'loginAttempts': '6/hr',
        'user': '1000/min',
    }
}