Django上下文处理器和csrf_token

时间:2014-01-08 01:05:03

标签: python django django-csrf

我有一个登录表单,我希望在所有视图中都可用,因此我创建了一个上下文处理器,将此表单添加到每个加载的上下文中。

问题是表单模板上的{% csrf_token %}不会使用CSRF令牌值呈现隐藏的输入标记。

这是settings.py中的context_processor顺序:

TEMPLATE_CONTEXT_PROCESSORS = (
    'django.contrib.auth.context_processors.auth',
    'django.core.context_processors.debug',
    'django.core.context_processors.i18n',
    'django.core.context_processors.media',
    'django.core.context_processors.static',
    'django.core.context_processors.tz',
    'django.contrib.messages.context_processors.messages',
    'django.core.context_processors.request',
    'django.core.context_processors.csrf',
    'absolute.context_processors.absolute',
    'myproject.app.context_processors.base',
)

然后处理器本身在app/context_processors.py

from django.contrib.auth.forms import AuthenticationForm

def base(request):
    context = dict()
    if not request.user.is_authenticated():
        context['login_form'] = AuthenticationForm()
    return context

表单模板:

{% load i18n %}

<form method="post" action="{% url "django.contrib.auth.views.login" %}">

    {% csrf_token %}
    <input type="hidden" name="next" value="{% if request.GET.next %}{{ request.GET.next }}{% else %}{{ request.get_full_path }}{% endif %}" />

    {{ login_form.as_p }}

    <input type="submit" class="button success expand" value="{% trans 'Login' %}" />

</form>

此表单的HTML输出:

<form action="/accounts/login/" method="post">


    <input type="hidden" value="/" name="next">

    <p><label for="id_username">Usuário:</label> <input type="text" name="username" maxlength="254" id="id_username"></p>
    <p><label for="id_password">Senha:</label> <input type="password" name="password" id="id_password"></p>

    <input type="submit" value="Login" class="button success expand">

</form>

提交时出现的错误:

CSRF verification failed. Request aborted.

但是,由于我只使用基于类的视图,如果我添加csrf_protect装饰器,表单将起作用,但是像这样我必须在我的所有方法中声明dispatch方法的观点:

from django.views.decorators.csrf import csrf_protect

class HomeView(TemplateView):
    template_name = 'home.html'

    @method_decorator(csrf_protect)
    def dispatch(self, *args, **kwargs):
        return super(HomeView, self).dispatch(*args, **kwargs)

问题状态

我放弃了通过创建登录表单页面将AuthenticationForm放在我的所有视图上。无论如何,如果有人可以帮我找到解决这个问题的方法,它仍然会很棒。

2 个答案:

答案 0 :(得分:3)

我花了几个小时来解决类似于你在此描述的问题。 {% csrf_token %}没有呈现任何内容,我在调试模式下看到了这一点:

  

defaulttags.py:66:UserWarning:模板中使用了{%csrf_token%},但上下文未提供该值。这通常是由于不使用RequestContext引起的。

我使用的是从TemplateView继承的简单视图:

class MenuIndexView(TemplateView):
    template_name = 'menu/index.html'

    def get_context_data(self, **kwargs):
        kwargs = super().get_context_data(**kwargs)

        session = self.request.session
        kwargs['zip_code'] = session.get('zip_code')
        kwargs['calendar'] = helpers.get_menu_calendar(date.today() + timedelta(days=1), timedelta(days=14))
        kwargs['forms'] = {'zip_code': forms.ZipCodeForm({'zip_code': session.get('zip_code')})}

        return kwargs

在Django&#39; s之后,我意识到在生成标记时几乎没有任何上下文可用(Django的CsrfTokeNode文件defaulttags.py

class CsrfTokenNode(Node):
    def render(self, context):
        csrf_token = context.get('csrf_token', None)
        if csrf_token:
            if csrf_token == 'NOTPROVIDED':
                return format_html("")
            else:
                return format_html("<input type='hidden' name='csrfmiddlewaretoken' value='{}' />", csrf_token)
        else:
            # It's very probable that the token is missing because of
            # misconfiguration, so we raise a warning
            if settings.DEBUG:
                warnings.warn(
                    "A {% csrf_token %} was used in a template, but the context "
                    "did not provide the value.  This is usually caused by not "
                    "using RequestContext."
                )
            return ''

在代码的这一点上,我只看到了上下文中的一个项目,并带有zip_code键。

我打开了主模板文件并意识到我犯了一个菜鸟错误 - 这是我的主要模板menu/index.html

{% extends 'base.html' %}

{% block content %}
    <div class="menu-order-meta zip_calendar">
        <div class="ink-grid align-center">
            <div class="column-group gutters half-vertical-padding medium">
                {% include 'partials/menu/zip-code.html' with zip_code=zip_code only %}
            </div>
        </div>
    </div>
{% endblock %}

我通过部分模板包含表单,并且我明确地限制了该部分模板中的可用上下文 - 注意with zip_code=zip_code only声明 - (通过这样做,隐式转换csrf_token上下文处理器不可用)。

答案 1 :(得分:0)

也许你错过了MIDDLEWARE_CLASSES中的django.middleware.csrf.CsrfViewMiddleware?

MIDDLEWARE_CLASSES = (
    ....
    'django.middleware.csrf.CsrfViewMiddleware',
    ....
)