CSRF avec Django, React+Redux avec Axios
c'est un projet éducatif, pas pour la production. Je n'avais pas l'intention d'avoir des logins utilisateurs dans le cadre de cela.
puis-je faire des appels postaux à Django avec un jeton CSRF sans avoir de login utilisateur? Puis-je le faire sans utiliser jQuery? Je suis hors de ma portée ici, et sûrement en train de confondre quelques concepts.
pour le côté JavaScript, j'ai trouvé ceci redux-csrf package. Je ne sais pas comment le combiner avec mon POST
action à l'aide d' 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"));
})
}
};
du côté de Django, j'ai lu cette documentation sur CSRF, et sur le travail général avec des vues basées sur la classe.
Voici mon avis pour l'instant:
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]))
j'ai essayé d'utiliser le csrf_exempt
décorateur juste pour ne pas avoir à se soucier de cela pour le moment, mais cela ne semble pas être comment cela fonctionne.
j'ai ajouté {% csrf_token %}
pour mon modèle.
C'est mon getCookie
méthode (vol à partir de 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;
}
j'ai lu que j'ai besoin de changer l'Axios CSRF info:
var axios = require("axios");
var axiosDefaults = require("axios/lib/defaults");
axiosDefaults.xsrfCookieName = "csrftoken"
axiosDefaults.xsrfHeaderName = "X-CSRFToken"
Où puis-je coller le jeton actuel, la valeur que j'obtiens en appelant <!--8?
7 réponses
Il y a trois façons. Vous pouvez inclure manuellement le token dans l'en-tête de chaque appel axios, vous pouvez définir xsrfHeaderName
dans chaque appel, ou définir une valeur par défaut xsrfHeaderName
.
1. Ajouter manuellement
disons que vous avez la valeur du jeton stockée dans une variable appelée csrfToken
. Définissez les en-têtes dans votre appel axios:
// ...
method: 'post',
url: '/api/data',
data: {...},
headers: {"X-CSRFToken": csrfToken},
// ...
2. Réglage xsrfHeaderName
à l'appel:
Ajouter ceci:
// ...
method: 'post',
url: '/api/data',
data: {...},
xsrfHeaderName: "X-CSRFToken",
// ...
Puis dans votre settings.py
fichier, ajoutez cette ligne:
CSRF_COOKIE_NAME = "XSRF-TOKEN"
3. Le réglage par défaut des en-têtes [1]
au lieu de définir l'en-tête dans chaque appel, vous pouvez définir des en-têtes par défaut pour axios.
dans le fichier où vous importez axios pour faire l'appel, ajoutez ceci sous vos importations:
axios.defaults.xsrfHeaderName = "X-CSRFToken";
Puis dans votre settings.py
le fichier, ajoutez cette ligne:
CSRF_COOKIE_NAME = "XSRF-TOKEN"
EDIT: apparemment, cela fonctionne un peu différemment avec Safari [2]
[1] à Partir de Dave Merwin
la confusion:
Django Docs
tout D'abord, tout le passage de la Django docs que James Evans référencés:
...sur chaque XMLHttpRequest, définissez un en-tête X-CSRFToken personnalisé la valeur du jeton CSRF. C'est souvent plus facile, parce que beaucoup de JavaScript les cadres fournissent des crochets qui permettent aux en-têtes d'être mis sur chaque demande.
dans un premier temps, vous devez obtenir le jeton CSRF lui-même. Recommandé la source du token est le cookie csrftoken, qui sera défini si vous avez activé la protection CSRF pour vos vues comme décrit ci-dessus.
Remarque:
le cookie de token CSRF est nommé csrftoken par défaut, mais vous pouvez contrôle du nom du cookie via le nom CSRF_COOKIE_NAME paramètre.
le nom de l'en-tête CSRF est HTTP_X_CSRFTOKEN par défaut, mais vous pouvez personnalisez-le en utilisant le paramètre CSRF_HEADER_NAME.
Axios Docs
C'est à partir de la Axios docs. Il indique que vous définissez le nom du cookie qui contient le csrftoken
, et le nom de l'en-tête ici:
// `xsrfCookieName` is the name of the cookie to use as a value for xsrf token
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
xsrfHeaderName: 'X-XSRF-TOKEN', // default
Termes
comme indiqué dans ma question, vous accédez cookies avec document.cookie
. Le seul cookie que j'ai est le jeton CSRF que j'ai mis dans le modèle Django. Voici un exemple:
csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU
il y a quelques concepts qui sont jetés dans ces docs qui deviennent confus:
- le nom du cookie qui contient le token CSRF. Dans Django c'est par défaut
csrftoken
, qui est sur le côté gauche du signe égal dans le cookie. - le jeton réel. C'est tout sur le côté droit de le signe égal dans le cookie.
- l'en-tête http qui contient la valeur du token.
je l'ai découvert, que axios.defaults.xsrfCookieName = "XCSRF-TOKEN";
et CSRF_COOKIE_NAME = "XCSRF-TOKEN"
DOESN't WORK IN APPLE Safari on Mac OS
la solution pour MAC Safari est facile,il suffit de changer XCSRF-TOKEN
csrftoken
Donc, dans js-code devrait être:
import axios from 'axios';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";