Подтвердить что ты не робот

Существует ли библиотека для предотвращения повторных представлений формы для django?

Я пытаюсь найти способ предотвратить двойное представление пользователями моих форм. У меня есть javascript, который отключает кнопку отправки, но есть еще случайный пользователь, который находит способ удвоить отправку.

У меня есть вид на многократно используемую библиотеку, которую я мог бы создать для защиты от этого.

В моей идеальной библиотеке блок кода будет выглядеть примерно так:

try:
    with acquire_lock({'field1':'abc', 'field2':'def'}) as lock:
        response = #do some credit card processing
        lock.response = response
except SubmissionWasDuplicate, e:
    response = e.response

Стол блокировки будет выглядеть примерно так:

duplicate_submission_locks

  • submit_hash # MD5 представленных аргументов
  • ответ # маринованные данные
  • created_at #, используемый для подметания этой таблицы
  • lock_expired # boolean, означающий, что срок действия блокировки истек.

Кто-нибудь знает, если это уже существует? Это, кажется, трудно писать, поэтому, если этого не существует, я могу написать его сам.

4b9b3361

Ответ 1

Одним из простых решений этой проблемы является добавление уникального хэша в каждую форму. Затем вы можете иметь таблицу текущих форм. Когда форма отправляется или хеш становится слишком старым, вы можете закончить его из своей таблицы и отклонить любую форму, которая не имеет соответствующего хэша в вашей таблице.

HTTPRedirect - это правильный способ сделать это, как упоминалось ранее.

К сожалению, даже встроенный администратор Django подвержен проблемам, связанным с этой проблемой. В некоторых случаях межсайтовая структура сценариев может помочь предотвратить некоторые из этих проблем, но я боюсь, что в нынешних производственных версиях этого встроенного устройства нет.

Ответ 2

Вы можете использовать сеанс для хранения хэша

import hashlib

def contact(request):
    if request.method == 'POST':
        form = MyForm(request.POST)
        #join all the fields in one string
        hashstring=hashlib.sha1(fieldsstring)
        if request.session.get('sesionform')!=hashstring:
            if form.is_valid() :                                         
                request.session['sesionform'] = hashstring
                #do some stuff...
                return HttpResponseRedirect('/thanks/') # Redirect after POST  
        else
           raise SubmissionWasDuplicate("duplicate")
    else:
        form = MyForm() 

При таком подходе (не удаляя файл cookie сеанса) пользователь не может повторно хранить данные, используя сеанс, и, кстати, я предполагаю, что существует что-то, кто идентифицирует пользователя, который отправляет данные.

Ответ 3

Честно говоря, ваш лучший выбор (простая и эффективная практика) заключается в том, чтобы выдать страницу HTTPRedirect() на страницу благодарности, и если страница с благодарностью совпадает с формой, это нормально. Вы все еще можете это сделать.

Ответ 4

Ответ Кристиана Дамиана - действительно большое предложение. Я просто подумал о небольшой вариации этой темы, но у нее может быть больше накладных расходов.

Вы можете попробовать реализовать что-то, что используется в django-piston для объектов BaseHandler, который является методом под названием exists(), который проверяет, находится ли то, что вы отправляете, в базе данных.

Из handler.py (BaseHandler):

def exists(self, **kwargs):
    if not self.has_model():
        raise NotImplementedError

    try:
        self.model.objects.get(**kwargs)
        return True
    except self.model.DoesNotExist:
        return False

Итак, предположим, что вместо функции request_exists() вызывается функция request_exists():

if form.is_valid()
    if request_exists(request):
        # gracefully reject dupe submission
    else:
        # do stuff to save the request
        ...
        # and ALWAYS redirect after a POST!!
        return HttpResponseRedirect('/thanks/') 

Ответ 5

Всегда полезно использовать метод redirect-after-post. Это предотвращает случайную повторную отправку формы с помощью функции обновления из браузера. Это также полезно, даже если вы используете хэш-метод. Это потому, что без перенаправления после POST, в случае нажатия кнопки "Назад/Обновить" пользователь увидит сообщение о повторной отправке формы, что может смутить ее.

Если вы выполняете перенаправление GET после каждого POST, то нажатие Back/Refresh не отображает это сообщение wierd (для обычного пользователя). Поэтому для полной защиты используйте Hash + redirect-after-post.