This is an educational project, not for production. I wasn't intending to have user logins as part of this.
Can I make POST calls to Django with a CSRF token without having user logins? Can I do this without using jQuery? I'm out of my depth here, and surely conflating some concepts.
For the JavaScript side, I found this redux-csrf package. I'm not sure how to combine it with my POST
action using Axios:
export const addJob = (title, hourly, tax) => {
console.log("Trying to addJob: ", title, hourly, tax)
return (dispatch) => {
dispatch(requestData("addJob"));
return axios({
method: 'post',
url: "/api/jobs",
data: {
"title": title,
"hourly_rate": hourly,
"tax_rate": tax
},
responseType: 'json'
})
.then((response) => {
dispatch(receiveData(response.data, "addJob"));
})
.catch((response) => {
dispatch(receiveError(response.data, "addJob"));
})
}
};
On the Django side, I've read this documentation on CSRF, and this on generally working with class based views.
Here is my view so far:
class JobsHandler(View):
def get(self, request):
with open('./data/jobs.json', 'r') as f:
jobs = json.loads(f.read())
return HttpResponse(json.dumps(jobs))
def post(self, request):
with open('./data/jobs.json', 'r') as f:
jobs = json.loads(f.read())
new_job = request.to_dict()
id = new_job['title']
jobs[id] = new_job
with open('./data/jobs.json', 'w') as f:
f.write(json.dumps(jobs, indent=4, separators=(',', ': ')))
return HttpResponse(json.dumps(jobs[id]))
I tried using the csrf_exempt
decorator just to not have to worry about this for now, but that doesn't seem to be how that works.
I've added {% csrf_token %}
to my template.
This is my getCookie
method (stolen from Django docs):
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 = cookies[i].trim();
// 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;
}
I've read that I need to change the Axios CSRF info:
var axios = require("axios");
var axiosDefaults = require("axios/lib/defaults");
axiosDefaults.xsrfCookieName = "csrftoken"
axiosDefaults.xsrfHeaderName = "X-CSRFToken"
Where do I stick the actual token, the value I get from calling getCookie('csrftoken')
?
For me, django wasn't listening to the headers that I was sending. I could curl into the api but couldn't access it with axios. Check out the cors-headers package... it might be your new best friend.
I fixed it by installing django-cors-headers
And then adding
and
into my settings.py
I also had
in my settings.py although that is probably overkill
You could add the Django-provided CSRF token manually into all of your post requests, but that's annoying.
From the Django docs:
The docs have code you can use to pull the CSRF token from the CSRF token cookie and then add it to the header of your AJAX request.
The "easy way" almost worked for me. This seems to work:
And in the settings.py file:
There is actually a really easy way to do this.
Add
axios.defaults.xsrfHeaderName = "X-CSRFToken";
to your app config and then setCSRF_COOKIE_NAME = "XSRF-TOKEN"
in your settings.py file. Works like a charm.I've found out, that
axios.defaults.xsrfCookieName = "XCSRF-TOKEN";
andCSRF_COOKIE_NAME = "XCSRF-TOKEN"
DOESN'T WORK IN APPLE Safari on Mac OS
The solution for MAC Safari is easy, just change
XCSRF-TOKEN
tocsrftoken
So, in js-code should be:
In settings.py:
This configuration works for me without problems Config axios CSRF django