3

我正在为移动应用程序制作后端,并使用 Django 和 Userena 进行用户管理。我使用 Django REST 框架登录并注册,一切正常。我现在唯一需要做的就是实现“忘记密码”功能。我想使用 Userena 中已经实现的一个,但即使在使用 dectorator 之后,我也无法摆脱错误“CSRF 令牌丢失或不正确” csrf_exempt。我在做什么?

网址.py

from django.contrib.auth.views import password_reset
from django.views.decorators.csrf import csrf_exempt
...
urlpatterns = patterns(
    '',
    url(r'^password/mobile/reset/$',
       csrf_exempt(password_reset),
       {'template_name': 'userena/password_reset_form.html',
        'email_template_name': 'userena/emails/password_reset_message.txt',
        'extra_context': {'without_usernames': userena_settings.USERENA_WITHOUT_USERNAMES}
        },
       name='userena_password_mobile_reset'),
)

passowrd_reset_form.html

{% extends 'userena/base_userena.html' %}
{% load i18n %}

{% block title %}{% trans "Reset password" %}{% endblock %}

{% block content %}
<form action="" method="post">
  <fieldset>
    <legend>{% trans "Reset Password" %}</legend>
    {% csrf_token %}
    {{ form.as_p }}
  </fieldset>
  <input type="submit" value="{% trans "Send password" %}" />
</form>
{% endblock %}
4

1 回答 1

7

如果您在 POST 到密码重置视图之前执行 GET 请求,您会在 cookie 中获得 CSRF 令牌,然后您可以将其发送到您的 POST 请求中。

如果你坚持豁免视图:我认为问题在于 CSRF 保护应用于password_reset视图的方式。它由 . 显式装饰csrf_protect

为了仔细研究这个问题,让我们假设original_password_reset_view没有. 基本上,您正在这样做:password_resetcsrf_protect

csrf_exempt(csrf_protect(original_password_reset_view))
# ^^ your code
#           ^^ the decorator in django.contrib.auth.views

加上 的效果CsrfViewMiddleware,我们得到等价于

csrf_protect(csrf_exempt(csrf_protect(original_password_reset_view)))

csrf_protect只是来自. _ 另一方面,只是简单地设置它的论点。因此,由 outer 表示的中间件会看到视图上的值并禁用其 CSRF 投影。它否定了外部。所以我们有:CsrfViewMiddlewarecsrf_exemptcsrf_exempt=Truecsrf_protectcsrf_exempt=True csrf_protect

csrf_protect(original_password_reset_view)

视图仍然受到保护。基本上,没有理智的方法。(一种疯狂的方式:编写一个request.csrf_processing_done = True为该特定 URL 设置的中间件。不要那样做......)

于 2013-12-19T20:38:25.767 回答