I am trying to create simple WEB application using Django and React. And last weekend I've spend in attempts to fix curious bug. As you may guess my Django application views use CSRF protection.
To provide the most proper CSRF setting I used that article from django project and just copy-paste that code:
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
into my index.js.
And $.post(...)
requests (outside React classes) like that:
function registration_post() {
var msg = $('#registration-form').serialize();
$.ajax({
type: 'POST',
url: '/users/',
data: msg,
success: function(data) {
if (typeof data === 'object') {
console.log('Account successfully created.');
console.log(data);
} else {
console.log('Some unnormal errors have been occurred. Here is your data:');
console.log(data);
}
},
error: function(xhr, str){
console.log(xhr);
}
});
}
works fine even without {% csrf_token %}
in the form. But when I tried to run $.post(...)
inside React classes I had in browser console that:
POST http://localhost:8000/expenses/ 403 (Forbidden)
Object {readyState: 4, responseText: "{"detail":"CSRF Failed: CSRF token missing or incorrect."}", responseJSON: Object, status: 403, statusText: "Forbidden"}
To fix it I tried that:
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", $('input[name=csrfmiddlewaretoken]').val());
}
}
});
And even that (each block of code in uncomment state of course):
var ExpenseBox = React.createClass({
postExpense(expense) {
$.ajax({
// beforeSend: function(xhr) {
// xhr.setRequestHeader('X-CSRFToken', csrftoken)
// },
// headers: {
// 'X-CSRFToken': csrftoken
// },
url: this.props.get_expenses_url,
type: 'POST',
dataType: 'json',
data: expense,
success: function(data) {
this.this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.log(xhr);
}.bind(this)
});
},
// other methods
});
But it did not help. I googled it. A lot. But most of all problems solves by refering post author to the link below or fixing some curious misspelling in code but not solving my case.
I tried to make post request in Django-REST-Framework API Test mode -- it works. So, problem not in the server side permission classes.
So. Any ideas what's wrong with it?
UPD 1
Request have csrf token. Here is an example:
POST /expenses/ HTTP/1.1
Host: localhost:8000
Connection: keep-alive
Content-Length: 34
Origin: http://localhost:8000
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
X-CSRFToken: jI0qKYZybfmV4PsG0jKULqNtqMZaD49e0cJsbQRXPoNuZggqq8rpA8z0mhQJBveG
Referer: http://localhost:8000/index/
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,ru;q=0.4
Cookie: tabstyle=html-tab; csrftoken=ELbOeq2HNCcXjvYasGihJrKnqw8ufZerQH9kHcTWylFOjstCJfgfMMVs1uX9XrNn; sessionid=7blm2q6bdmf9la2eiu7xzywznvzlnv8y