18

ユーザーがフォームを二重に送信しないようにする方法を見つけようとしています。送信ボタンを無効にする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#ロックの有効期限が切れているかどうかを示すブール値

これがすでに存在するかどうか誰かが知っていますか?書くのは難しいことではないようですので、存在しない場合は自分で書くかもしれません。

4

5 に答える 5

12

セッションを使用してハッシュを保存できます

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を削除しない)では、ユーザーはセッションが期限切れになるまでデータを復元できません。ちなみに、データを送信するユーザーを識別する何かが存在すると想定しています。

于 2010-01-28T20:24:25.587 に答える
6

この問題の簡単な解決策の1つは、各フォームに一意のハッシュを追加することです。次に、現在のフォームのローリングテーブルを作成できます。フォームが送信された場合、またはハッシュが古くなりすぎた場合は、テーブルからフォームを期限切れにして、テーブルに一致するハッシュがないフォームを拒否できます。

前述のように、HTTPRedirectはそれを行う正しい方法です。

残念ながら、Django独自の組み込み管理者でさえ、この問題に関連する問題が発生する傾向があります。場合によっては、クロスサイトスクリプティングフレームワークがこれを防ぐのに役立つことがありますが、現在の製品バージョンにはこれが組み込まれていないのではないかと思います。

于 2010-01-26T07:48:27.993 に答える
3

クリスチャン・ダミアンの答えは本当に素晴らしい提案です。そのテーマのわずかなバリエーションを考えただけですが、オーバーヘッドが大きくなる可能性があります。

オブジェクトの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()、メソッドの代わりに、という関数を作成するとします。

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/') 
于 2010-02-04T16:41:20.897 に答える
3

正直なところ、最善の策(簡単で良い習慣)は、ありがとうページにHTTPRedirect()を発行することです。ありがとうページがフォームと同じであれば、それで問題ありません。あなたはまだこれを行うことができます。

于 2010-01-26T05:19:15.930 に答える
2

ポスト後のリダイレクト方法を使用することは常に良いことです。これにより、ユーザーがブラウザの更新機能を使用して誤ってフォームを再送信するのを防ぐことができます。ハッシュ方式を使用する場合にも役立ちます。これは、POST後にリダイレクトしない場合、[戻る] / [更新]ボタンを押すと、ユーザーにフォームの再送信に関する質問メッセージが表示され、混乱する可能性があるためです。

POSTごとにGETリダイレクトを実行する場合、[戻る] / [更新]をクリックしても、この奇妙な(通常のユーザーの場合)メッセージは表示されません。したがって、完全に保護するには、Hash+redirect-after-postを使用します。

于 2010-01-27T13:23:43.483 に答える