CSRF с Django, React+Redux с использованием Axios
это образовательный проект, не для производства. Я не собирался иметь логины пользователей как часть этого.
могу ли я совершать почтовые звонки в Django с токеном CSRF без входа пользователя? Могу ли я сделать это без использования jQuery? Я здесь не в своей тарелке и, конечно же, смешиваю некоторые концепции.
для стороны JavaScript я нашел это redux-csrf пакета. Я не уверен, как совместить его с моим POST
действие с использованием Аксиос:
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"));
})
}
};
на стороне Джанго, я прочитал документация на CSRF, и этой о работе с представлениями на основе классов.
вот мой взгляд до сих пор:
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]))
Я попытался с помощью csrf_exempt
декоратор просто не нужно беспокоиться об этом сейчас, но это, похоже, не так, как это работает.
я добавил {% csrf_token %}
в моем шаблоне.
это мой getCookie
метод (украденный из документов Django):
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;
}
я читал что мне нужно изменить информацию Axios CSRF:
var axios = require("axios");
var axiosDefaults = require("axios/lib/defaults");
axiosDefaults.xsrfCookieName = "csrftoken"
axiosDefaults.xsrfHeaderName = "X-CSRFToken"
куда мне вставить фактический токен, значение, которое я получаю от вызова getCookie('csrftoken')
?
7 ответов
есть три способа. Вы можете вручную включить токен в заголовок каждого вызова axios, вы можете установить axios xsrfHeaderName
в каждом вызове, или установить по умолчанию xsrfHeaderName
.
1. Добавление вручную
предположим, у вас есть значение токена, хранящееся в переменной csrfToken
. Установите заголовки в вызове axios:
// ...
method: 'post',
url: '/api/data',
data: {...},
headers: {"X-CSRFToken": csrfToken},
// ...
2. Настройка xsrfHeaderName
в звонок:
добавить это:
// ...
method: 'post',
url: '/api/data',
data: {...},
xsrfHeaderName: "X-CSRFToken",
// ...
затем в settings.py
файл, добавьте эту строку:
CSRF_COOKIE_NAME = "XSRF-TOKEN"
3. Установка заголовков по умолчанию[1]
вместо определения заголовка в каждом вызове можно задать заголовки по умолчанию для axios.
в файле, куда вы импортируете axios для выполнения вызова, добавьте это ниже импорта:
axios.defaults.xsrfHeaderName = "X-CSRFToken";
затем в settings.py
файл, добавьте эту строку:
CSRF_COOKIE_NAME = "XSRF-TOKEN"
редактировать: по-видимому, он работает немного иначе с Сафари[2]
[1] от Дэйва Мервина комментарий
растерянность:
Django Docs
во-первых, весь отрывок из Django docs этот Джеймс Эванс ссылка:
...для каждого XMLHttpRequest установите пользовательский заголовок X-CSRFToken в значение CSRF токен. Это часто проще, потому что многие Яваскрипт фреймворки предоставляют крючки, которые позволяют устанавливать заголовки на каждом запрос.
в качестве первого шага вы должны получить сам токен CSRF. Рекомендуемый источником токена является файл cookie csrftoken, который будет установлен, если вы включили защиту CSRF для ваших представлений, как описано выше.
Примечание
файл cookie маркера CSRF по умолчанию называется csrftoken, но вы можете управление именем cookie с помощью CSRF_COOKIE_NAME установочный.
имя заголовка CSRF по умолчанию HTTP_X_CSRFTOKEN, но вы можете настройте его с помощью параметра CSRF_HEADER_NAME.
Axios Docs
это Axios docs. Это означает, что вы задаете имя файла cookie, который содержит csrftoken
, и название заголовка здесь:
// `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
условия
как указано в моем вопросе, вы получаете доступ к cookies с document.cookie
. Только печенье у меня есть CSRF токен я вставил в шаблон Django. Вот пример:
csrftoken=5knNceCUi9nL669hGGsvCi93XfqNhwTwM9Pev7bLYBOMXGbHVrjitlkKi44CtpFU
в этих документах есть несколько концепций, которые сбивают с толку:
- имя файла cookie, содержащего маркер CSRF. В Django это по умолчанию
csrftoken
, который находится в левой части знака равенства в файле cookie. - фактический маркер. Это все на правильной стороне равных. знак в cookie.
- заголовок http, который несет значение токена.
я выяснил, что axios.defaults.xsrfCookieName = "XCSRF-TOKEN";
и CSRF_COOKIE_NAME = "XCSRF-TOKEN"
не работает в Apple Safari на Mac OS
решение для Mac Safari легко,просто изменить XCSRF-TOKEN
до csrftoken
Итак, в js-коде должно быть:
import axios from 'axios';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
In settings.py:
CSRF_COOKIE_NAME = "csrftoken"
"легкий путь" почти сработал для меня. Это, кажется, работает:
import axios from 'axios';
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "XCSRF-TOKEN";
и в settings.py файл:
CSRF_COOKIE_NAME = "XCSRF-TOKEN"
эта конфигурация работает у меня без проблем конфигурация axios CSRF django
import axios from 'axios'
/**
* Config global for axios/django
*/
axios.defaults.xsrfHeaderName = "X-CSRFToken"
axios.defaults.xsrfCookieName = 'csrftoken'
export default axios
вы можете добавить маркер CSRF, предоставленный Django, вручную во все ваши запросы post, но это раздражает.
с Django docs:
пока вышеуказанный метод (ручная настройка маркера CSRF) может использоваться для запросов AJAX POST, у него есть некоторые неудобства: вы должны помнить, чтобы передать токен CSRF в качестве данных POST с каждым запросом POST. По этой причине, существует альтернативный метод: на каждый запрос, установить пользовательский заголовок X-CSRFToken для значения маркера CSRF. Это часто проще, потому что многие фреймворки JavaScript предоставляют крючки, которые позволяют устанавливать заголовки для каждого запроса.
в документах есть код, который вы можете использовать, чтобы вытащить токен CSRF из файла cookie токена CSRF, а затем добавить его в заголовок вашего запроса AJAX.
есть очень простой способ сделать это.
добавить axios.defaults.xsrfHeaderName = "X-CSRFToken";
в конфигурацию приложения, а затем установите CSRF_COOKIE_NAME = "XSRF-TOKEN"
в вашем settings.py файл. Работает как заклинание.
для меня, Джанго не слушал заголовки, которые я посылал. Я мог свернуться в api, но не мог получить к нему доступ с помощью axios. Проверьте пакет заголовков cors... это может быть твой новый лучший друг.
я исправил это, установив django-cors-headers
pip install django-cors-headers
и затем добавить
INSTALLED_APPS = (
...
'corsheaders',
...
)
и
MIDDLEWARE = [ # Or MIDDLEWARE_CLASSES on Django < 1.10
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
]
в мой settings.py
у меня тоже было
ALLOWED_HOSTS = ['*']
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
CORS_EXPOSE_HEADERS = (
'Access-Control-Allow-Origin: *',
)
в моем settings.py хотя это вероятно, это перебор