D
D
David52020-02-07 13:09:51
Django
David5, 2020-02-07 13:09:51

Ban by IP for a while?

Hello, I have a form (fixed photo) so that after submitting the form, the IP of this person is banned for a while, he can browse the site, but nothing happens when submitting the form, or he gets an error that so much time is left. This is necessary in order to so that all sorts of clever people don’t spam the admin panel with left applications.5e3d376163420503398412.png

Answer the question

In order to leave comments, you need to log in

2 answer(s)
Сергей Горностаев, 2020-02-07
@David5

Подключаете примерно такую мидлварь

def _get_ending(n, endings):
    n = n % 100
    if n >= 11 and n <= 19:
        return endings[2]
    else:
        n = n % 10
        if n == 1:
            return endings[0]
        elif n > 1 and n < 5:
            return endings[1]
        else:
            return endings[2]


def _get_message(limit):
    if limit > 3660:
        limit //= 3600
        endings = [_('часа'), _('часов'), _('часов')]
    elif limit > 60:
        limit //= 60
        endings = [_('минуты'), _('минут'), _('минут')]
    else:
        endings = [_('секунды'), _('секунд'), _('секунд')]
    return _('Форма отправлялась менее {} {} назад').format(limit, _get_ending(limit, endings))


def post_limit_middleware(get_response):
    limits = getattr(settings, 'REQUEST_LIMITS', {})

    def middleware(request):
        if request.method == 'POST':
            match = resolve(request.path_info)
            name = '{}:{}'.format(match.namespace, match.url_name) if match.namespace else match.url_name
            limit = limits.get(name)
            if limit is not None:
                now = datetime.now()
                user_id = request.user.username if request.user.is_authenticated else get_ip(request)
                key = hashlib.md5(user_id.encode()).hexdigest()
                cache_name = 'last-request.{0}.{1}'.format(name, key)
                last_request = cache.get(cache_name, now - timedelta(days=1))
                if (now - last_request) < timedelta(seconds=limit):
                    cache.set(cache_name, now)

                    if request.is_ajax():
                        response = JsonResponse([_get_message(limit)], safe=False)
                        response.status_code = 429
                    else:
                        response = render(request, '429.html', {'message': _get_message(limit)})
                        response.status_code = 429
                    return response
                else:
                    cache.set(cache_name, now)
        response = get_response(request)
        return response

    return middleware

Прописывается в settings.py настройку вида
REQUEST_LIMITS = {
    'contact_form': 3600,
}

И живёте спокойно.

V
Vladimir Kuts, 2020-02-07
@fox_12

If you use cache - I would do it easier. Provided that in ip - ip-address:

from django.core.cache import cache

IP_KEY = 'request_ban:{ip}'
DELAY = 3600

result = cache.get(IP_KEY.format(ip=ip))
if result:
     difference = (result - datetime.datetime.now()).seconds
     print(f'Вам осталось {difference} секунд')
else:
     cache.set(
          IP_KEY.format(ip=ip),
          datetime.datetime.now() + datetime.timedelta(seconds=DELAY),
          DELAY,
     )
     print('Добро пожаловать!')

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question