I maintain a simple Django web application where users congregate and leave each other text + photo messages. The server employs SSL. I also use a CDN to serve static assets, in case that matters.
My problem is that upon trying to log in an existing user, I get a CSRF Verification failed error. Peculiarly, many users report getting this error the first time they try logging in, but that it works the second time around right after. Also, a proxy is involved in between - all the reporters of this error are on the said proxy. Without the proxy, it works perfectly. Looking at Resources in Developer Tools for Chrome, I've found that the CSRF token is correctly present when the website is accessed without the proxy in the middle, but is entirely missing when on the proxy.
What special measures am I to take on this?
I use a vanilla logging in process, i.e. a contrib function. In my urls.py, I have the url pattern:
url(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}, name="login"),
In settings.py, I have:
MIDDLEWARE_CLASSES = (
# 'debug_toolbar.middleware.DebugToolbarMiddleware',
'myproject.middleware.XForwardedFor.XForwardedForMiddleware',
'user_sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
#'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'myproject.middleware.HellBanned.HellBannedMiddleware',
#'request.middleware.RequestMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'mobileesp.middleware.MobileDetectionMiddleware',
# Uncomment the next line for simple clickjacking protection:
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
Whereas the login function in views.py found in django.contrib.auth is:
@sensitive_post_parameters()
@csrf_protect
@never_cache
def login(request, template_name='registration/login.html',
redirect_field_name=REDIRECT_FIELD_NAME,
authentication_form=AuthenticationForm,
current_app=None, extra_context=None):
"""
Displays the login form and handles the login action.
"""
redirect_to = request.REQUEST.get(redirect_field_name, '')
if request.method == "POST":
form = authentication_form(data=request.POST)
if form.is_valid():
# Ensure the user-originating redirection url is safe.
if not is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)
# Okay, security check complete. Log the user in.
auth_login(request, form.get_user())
if request.session.test_cookie_worked():
request.session.delete_test_cookie()
return HttpResponseRedirect(redirect_to)
else:
form = authentication_form(request)
request.session.set_test_cookie()
current_site = get_current_site(request)
context = {
'form': form,
redirect_field_name: redirect_to,
'site': current_site,
'site_name': current_site.name,
}
if extra_context is not None:
context.update(extra_context)
return TemplateResponse(request, template_name, context,
current_app=current_app)
Is the above function missing anything? BTW, my login template is quite simply:
{% extends "base.html" %}
{% block content %}
<div class="margin">
<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
<p>{{ 'Nickname:' }}
{{ form.username }}</p>
<p> {{ 'Password:' }}
{{ form.password }}</p>
<input class="button" type="submit" value="OK"><br>
</form>
<br>
</div>
{% endblock %}
Ideally, I don't want to use csrf exempt, since I feel that's a workaround, and doesn't really untangle this tangle.
Can anyone please advise what I need to do? I've seen similar questions asked on SO before, but they don't work for me because:
here: this OP had written an erroneous method in views.py, whereas I'm simply relying on the vanilla django.contrib.auth.views.login method. As the docs state: If you’re using the render() function, generic views, or contrib apps, you are covered already since these all use RequestContext.
here: Same problem as above it seems.
here: this OP was missing {% csrf_token %} in her Django template, I'm not.
Thanks in advance. I'm a newbie in this domain, so apologies if the solution is obvious and it's eluding me. Btw, in case it matters, I employ legacy Django (v 1.5.1) for this particular project.