djangoで多重submitを制御する

2022年5月3日

djangoで多重submitを制御する

前回はクライアント側で多重submitを防ぐ為に、ボタンが押されたらボタンを非アクティブにして二度押せないように処理を加えました。

前回の記事:jQueryでボタンの二重クリックを制御する

しかしjavascriptで制御している場合、ブラウザの機能でjavascriptを無効にすることが出来てしまいます。なのでサーバー側でも制御を入れてあげる必要があります。今回djangoで制御してみたので記事に残したいと思います。

参考:Djangoで二重サブミット抑止

「セッションに格納したトークン」とサブミットされてきた「トークン」が一緒かどうか確認していますが、更に一度使用されたトークンを「pop」で破棄する事で多重サブミットを検知する仕組です。参考と違いますが、私の環境では「pop」が大文字だと機能しませんでした。

動きは下の通りです。

階層

階層は下の通りです。


.
├── app
│   ├── urls.py
│   ├── views_modules
│   │   └── security.py
│   └── views.py
└── templates
    └── app
       └── test_token_check.html

「トークンの生成」「セッションに格納」「セッションのチェック」は「security.py」が請け負っています。

コード

security.pyは下の通りです。
説明はコード内に記載しました。


#--ハッシュ値生成--------------------------------------
import uuid
def set_submit_token(request):
    #ハッシュ値生成
    submit_token = str(uuid.uuid4())
    #セッションにトークンを格納
    request.session['submit_token'] = submit_token
    #クライアント用に同じ値のトークンを返す
    return submit_token
def exist_submit_token(request):
    #クライアントから送信されたトークンを取得
    token_in_request = request.POST.get('submit_token')
    #一度使用したトークンだった場合セッションから破棄
    token_in_session = request.session.pop('submit_token', '')
    if not token_in_request:
        return False
    if not token_in_session:
        return False
    return token_in_request == token_in_session

views.pyは下の通りです。
レスポンス→「submit_token = security.set_submit_token(request)」でトークン発行
リクエスト→「if security.exist_submit_token(request):」でトークンチェック


#--トークンテスト--------------------------------------
def test_token_check(request):
    if request.method == "POST":
        if security.exist_submit_token(request):
            comment = '正常にクリックが行われました'  
        else:
            comment = '多重クリックが行われました'
    else:
        comment = 'クリックの判定を行います'
    submit_token = security.set_submit_token(request)
    context = {
        'comment': comment,
        'submit_token': submit_token,
    }
    return render(request, 'app/test_token_check.html', context)

test_token_check.htmlは下の通りです。
「<input type="text" name="submit_token" value="{{ submit_token }}" class="input_box">」には、生成されたトークンが格納されています。ボタンを押すとこれがサーバーに再度送信されます。
使用する時は「hidden」にしましょう。


{% extends 'app/base.html' %}
{% block content %}
{% load widget_tweaks %}
<div>{{ comment }}</div>
<form method="post" action="{% url 'app:test_token_check' %}">{% csrf_token %}
    <input type="text" name="submit_token" value="{{ submit_token }}" class="input_box">
    <button type="submit" class="positive_button">submit</button>
</form>
{% endblock %}

あとは「views.py」の「if」「else」にそれぞれの処理を入れてあげましょう。

2022年5月3日