403s登录后重新提交表格

时间:2015-01-11 22:49:06

标签: django django-forms

我在以下重复步骤下得到403:

  1. 注销后,尝试提交生成验证错误的Django表单
  2. 登录或注册有效帐户
  3. 使用浏览器返回带有验证错误的页面
  4. 重新提交表单
  5. 结果:403错误。这很可能是预期的行为,但我正在寻找一种更优雅的方式来处理这个问题。是否有一种很好的方法来捕获这个并重新提交表单作为登录用户?

2 个答案:

答案 0 :(得分:3)

我已经在许多框架的上下文中看到了这个问题,唯一优雅的解决方案是JavaScript。

使用JavaScript,您可以将输入值存储在localStorage中。然后在成功的表单提交事件中,清除这些值。如果表单加载了localStorage中存在的那些值(表单提交返回403,并且用户返回到表单页面),则自动使用值填充表单。

实施起来并不复杂,只需要做更多的工作。我相信有基于这个想法的JS库......

  1. 为所有表单元素指定一个类名。在示例中,我将使用store-data。如果您在django中定义表单,则可以在forms.Widget.attrs中设置,如果您编写自己的html,则可以在输入元素上使用class属性设置。

  2. 在提交时,将名为formData的项目添加到localStorageformData是一个JS对象映射表单字段元素id,其中classname从上面到元素值。

  3. 如果表单已提交并处理为有效,请在重定向页面上使用formDatalocalStorage移除localStorage.removeItem()

  4. 加载表单页面时(这是用户在403之后返回表单的位置),如果formData中存在localStorage,则将值加载到表单字段中。

  5. 以下是实施此示例的示例:

    <form name="myForm" action="{% url 'myapp:form_submit' %}" onsubmit="return storeData()">
        <label>Name: </label>
        <input type="text" class="store-data" id="inputName" />
    
        <label>Description: </label>
        <textarea class="store-data" id="textareaDescription"></textarea>
    
        <input type="submit" />
    </form>
    <script>
    function storeData() {
        var elements = document.getElementsByClassName("store-data");
        var formData = {};
    
        // store element ids and values in formData obj
        for (var i = 0; i < elements.length; i++) {
            formData[elements[i].id] = elements[i].value;
        }
    
        // store formData to localStorage as string
        localStorage.setItem('formData', JSON.stringify(formData));
    }
    
    // if the localStorage item has already been set, then the user tried to submit and failed
    if (localStorage.getItem('formData')) {
        formData = JSON.parse(localStorage.getItem('formData'))
        // set all the form elements to the values that were stored when the user tried to submit
        for (var key in formData) {
            document.getElementById(key).value = formData[key];
        }
    }
    </script>
    

    在重定向的成功页面上,请务必删除formData项。否则,只要用户返回表单,值就会被加载到字段中。 (我想这可能是一种理想的行为,但我对此表示怀疑。)

    <script>
    localStorage.removeItem('formData');
    </script>
    

答案 1 :(得分:2)

嗯,是的,这是预期的行为。登录时,会生成新的csrf_token。当您导航回带有验证错误的页面时,它仍然包含<input type="hidden" name="csrfmiddlewaretoken" value="old_token" />中的旧csrf_token。因此,您使用无效的csrf_token提交表单并获得403错误。

我可以为你推荐两种选择(我不喜欢它们)

  1. 在登录时禁用新的csrf_token生成。只需在request.META['CSRF_COOKIE_USED'] = False之后将login(request, user)放在您的登录视图中。

  2. 为您的单个视图停用csrf保护via decorator,或从settings.py中删除csrf middleware全局。