5
votes

I receive this message:

CSRF token missing or incorrect.

In most forums, the tell you to get the {% csrf_token %} in the form, and i do have it.

Also i have in my settings.py:

TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.csrf",
"django.contrib.auth.context_processors.auth",
)

I am using jinja, which didn't seem to use CSRF, but then i installed django registration and i got lost, since, it seems to be using some other views, that i don't have access to so to say, they are not written by me, and i can't figure out where they are. "standard auth views" as they call them. So i am unable to add "RequestContext".

Any ideas what's going on and how I can get it going? thanx

5
what does your template look like?JonC
{% extends "site_base.html" %} {% block body %} <form method="post" action="/accounts/login/"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="Submit" /> <input type="hidden" name="next" value="{{ next }}" /> </form> {% endblock body %}mgPePe

5 Answers

3
votes

You might have to rewrite the django-registration view manually. Looks like there's an issue with how Jinja likes to do things and how Django wants to configure template loaders..

To look at the standard auth views, just look under "site-packages" in your python installation.

You could try wrapping the standard auth views like this:

from django.contrib.auth.views import login, logout
from django.views.decorators.csrf import csrf_protect

@csrf_protect
def my_wrapped_login_view(request):
    return login(request)

@csrf_protect
def my_wrapped_logout_view(request):
    return logout(request)

I basically imported Django's standard auth views and called them with my own, which have the csrf_protect decoration. It's worth a shot.

2
votes

Have you also got the standard Django Templating system installed? That will be required for most apps that are distributed with templates.

For CSRF, a context processor inserts the variable 'csrf_token' into the response context that it retrieves from the middleware if enabled. Now all you have to do, is make sure that it's apart of your form.

This is straight out of django.core, and is subject to change at any time.

        if csrf_token:
            if csrf_token == 'NOTPROVIDED':
                return mark_safe(u"")
            else:
                return mark_safe(u"<div style='display:none'><input type='hidden' name='csrfmiddlewaretoken' value='%s' /></div>" % csrf_token)

However, seeing that, all you really need to know is that you have to have an input type named csrfmiddlewaretoken with the value of context.get('csrf_token','') within your form and that's all she wrote.

2
votes

This answer isn't specific to django-registration, but just using Django with Jinja2 in general.

Django's CsrfViewMiddleware sets the csrf_token cookie if it determines that you have accessed the csrf_token context member. Unfortunately, Jinja2 rendering doesn't occur until after Django's middleware executes. As a result, the cookie doesn't get set, and therefore does not match the form, and you will get the 403 error.

To get around this issue, you need to access context['csrf_token'] at some point before you finish processing the response.

If you're using class-based views, you can create a CsrfProtectMixin:

class CsrfProtectMixin(object):
    def render_to_response(self, context, **response_kwargs):
        # Csrf processing happens when using a RequestContext. 
        # Be sure to use one.
        if not isinstance(context, RequestContext):
            context = RequestContext(self.request, context)

        # Force access to csrf_token due to the way jinja2 renders the template
        # after middleware has finished processing. Otherwise, the csrf cookie
        # will not be set.
        str(context.get('csrf_token'))

        return super(CsrfProtectMixin, self).render_to_response(context, **response_kwargs)

And then in your view class:

class MyView(CsrfProtectMixin, TemplateView):
    def get(self, request, *args, **kwargs):
        context = {}
        return self.render_to_response(context)

If you're not using class-based views, you can do something like:

def my_view(request):
    context = RequestContext(request)
    str(context['csrf_token']) #force access to the csrf_token
    return render_to_response('template.html', context)

Or perhaps monkey patch render_to_reponse with the logic in the class, above.

0
votes

The most straightforward answer to this one is to just put {% csrf_token %} within the form tag in your template/html.

-6
votes

I just switched off the csrf middleware in the settings like so, and now it works:

    #'django.middleware.csrf.CsrfViewMiddleware',