403s 登录后重新提交表单
403s resubmitting a form after login
我在以下重现步骤下得到了 403:
- 注销后,尝试提交生成验证错误的 Django 表单
- 登录或注册有效帐户
- 使用浏览器返回验证错误的页面
- 重新提交表单
结果:403错误。这很可能是预期的行为,但我正在寻找一种更优雅的方式来处理这个问题。有什么好的方法可以捕捉到这一点并以登录用户身份重新提交表单?
嗯,是的,这是预期的行为。当您登录时,会生成新的 csrf_token。当您导航回出现验证错误的页面时,它仍然包含 <input type="hidden" name="csrfmiddlewaretoken" value="old_token" />
中的旧 csrf_token。所以你提交无效的表单 csrf_token 并得到 403 错误。
我可以为您推荐两个选项(none 个我喜欢)
登录时禁用新的 csrf_token 生成。只需在您的登录视图中将 request.META['CSRF_COOKIE_USED'] = False
放在 login(request, user)
之后。
禁用 settings.py 的 csrf 保护 via decorator for your single view, or globally by removing csrf middleware。
我在很多框架的上下文中看到过这个问题,唯一优雅的解决方案是JavaScript。
使用 JavaScript,您可以将输入值存储在 localStorage
中。然后在成功的表单提交事件中,清除这些值。如果表单加载了 localStorage
中存在的那些值(表单提交返回 403,用户返回表单页面),则自动使用这些值填充表单。
实施起来并不复杂,只是需要更多的工作。我相信有基于这个想法的 JS 库...
为所有表单元素指定一个类名。在示例中,我将使用 store-data
。如果您在 django 中定义表单,则可以在 forms.Widget.attrs
中设置,或者如果您编写自己的 html.
[=51,则只需在输入元素上使用 class
属性=]
提交后,将名为 formData
的项目添加到 localStorage
。 formData
是一个 JS 对象映射表单字段元素 ids,从上面的类名到元素值。
如果表单被提交并处理为有效,在重定向页面上从 localStorage
中删除 formData
和 localStorage.removeItem()
。
加载表单页面时(这将是用户在 403 之后返回到表单的地方),如果 formData
存在于 localStorage
中,则将值加载到表单字段。
这是一个实现了此功能的示例表单:
<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>
我在以下重现步骤下得到了 403:
- 注销后,尝试提交生成验证错误的 Django 表单
- 登录或注册有效帐户
- 使用浏览器返回验证错误的页面
- 重新提交表单
结果:403错误。这很可能是预期的行为,但我正在寻找一种更优雅的方式来处理这个问题。有什么好的方法可以捕捉到这一点并以登录用户身份重新提交表单?
嗯,是的,这是预期的行为。当您登录时,会生成新的 csrf_token。当您导航回出现验证错误的页面时,它仍然包含 <input type="hidden" name="csrfmiddlewaretoken" value="old_token" />
中的旧 csrf_token。所以你提交无效的表单 csrf_token 并得到 403 错误。
我可以为您推荐两个选项(none 个我喜欢)
登录时禁用新的 csrf_token 生成。只需在您的登录视图中将
request.META['CSRF_COOKIE_USED'] = False
放在login(request, user)
之后。禁用 settings.py 的 csrf 保护 via decorator for your single view, or globally by removing csrf middleware。
我在很多框架的上下文中看到过这个问题,唯一优雅的解决方案是JavaScript。
使用 JavaScript,您可以将输入值存储在 localStorage
中。然后在成功的表单提交事件中,清除这些值。如果表单加载了 localStorage
中存在的那些值(表单提交返回 403,用户返回表单页面),则自动使用这些值填充表单。
实施起来并不复杂,只是需要更多的工作。我相信有基于这个想法的 JS 库...
为所有表单元素指定一个类名。在示例中,我将使用
[=51,则只需在输入元素上使用store-data
。如果您在 django 中定义表单,则可以在forms.Widget.attrs
中设置,或者如果您编写自己的 html.class
属性=]提交后,将名为
formData
的项目添加到localStorage
。formData
是一个 JS 对象映射表单字段元素 ids,从上面的类名到元素值。如果表单被提交并处理为有效,在重定向页面上从
localStorage
中删除formData
和localStorage.removeItem()
。加载表单页面时(这将是用户在 403 之后返回到表单的地方),如果
formData
存在于localStorage
中,则将值加载到表单字段。
这是一个实现了此功能的示例表单:
<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>