I have a problem with the CSRF token mechanism in Django that only occurs in Firefox and Internet Explorer (Chrome seems to work just fine). My site serves a page which performs an AJAX call once the page is ready()
. When the AJAX call is issued, I get a 403 Forbidden error stating CSRF verification failed. Request aborted. The reason given by the error page is CSRF cookie not set.
I've already looked at Django CSRF check failing with an Ajax POST request, and I'm following the accepted answer there. However, I still see problems in 2 out of 3 browsers.
When I inspect the headers for this call, I see the csrftoken
being set properly, but the value doesn't match the value set in the page!
(I was wrong about the values not matching. The "View Source" option in Firefox apparently reloads the page, rather than show the source of the page you're viewing.)
My server was set up by following this article, though I'm using SQLite at the moment over Postgres. Why should I be getting 403 errors when the token is being passed properly?
Here's my AJAX call:
$.ajax({
beforeSend: function(xhr, settings) {
csrftoken = getCookie('csrftoken');
if(!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
},
url: "{% url 'cap_plan:ajax_get_chart_data' %}",
type: "POST",
success: drawChart,
error: function(xhr, errmsg, err) {
// TODO: Do something better in the error case
console.log("AJAX Error!");
console.log(xhr.status + ": " + xhr.responseText);
}
});
The getCookie()
and csrfSafeMethod
routines are the exact ones listed in the official CSRF documentation.
Here's the URL rule that's put into play for this call:
url(r'^ajax/get_chart_data/$', ajax_get_chart_data, name='ajax_get_chart_data'),
And here's a simplified look at the respective view for the overall page:
@ensure_csrf_cookie
def cap_plan_overview(request):
return render_to_response('cap-plan-overview.html',
{}, context_instance=RequestContext(request))
And the view for the AJAX call itself (again, simplified):
def ajax_get_chart_data(request):
if request.method == 'POST':
// Do a bunch of work getting data; put it in the response dict
return HttpResponse(
json.dumps(response),
content_type="application/json"
)
else:
return HttpResponse(
json.dumps({error: "Invalid AJAX call to ajax_get_chart_data"}),
content_type="application/json"