Django CSRF-токен с POST выбрасывает 403 из-за отсутствия заголовка Origin
Нужно перенести старый проект с Python 2.7 & Django 1.9 на Python 3.10 & Django 4.1.
Здесь также есть куча кода JavaScript, о котором я имею лишь общее представление.
Stuck борется с кодом 403 при POST запросе от url к другому из-за важной защиты CSRF:
Помощь
Причина неудачи:
Origin checking failed - null does not match any trusted origins.
В общем, это может произойти, когда существует настоящий Cross Site Request Request Forgery, или когда механизм CSRF в Django был использован неправильно. Для POST форм вам необходимо убедиться в том, что:
Your browser is accepting cookies. The view function passes a request to the template’s render method. In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL. If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as
и те, которые принимают POST-данные. Форма имеет действительный CSRF-токен. После входа в систему на другой вкладке браузера или нажатия кнопки "назад" после входа, вам может потребоваться перезагрузить страницу с формой, так как маркер сменяется после входа в систему.
Вы видите раздел справки на этой странице, потому что у вас установлено DEBUG = True в вашем файле настроек Django. Измените это значение на False, и только будет отображаться только начальное сообщение об ошибке.
Вы можете настроить эту страницу, используя параметр CSRF_FAILURE_VIEW.
Просмотрел СЦ и не нашел близкого решения.
Насколько удалось выяснить, JavaScript генерирует JSON Response как положено, а именно:
{"oneParameter": [[18, 0.1], [19, 0.5], [20, 1.0], [21, 3.0], [22, 4.0], [23, 6.0]], "anotherParameter": [[33, -3], [34, -5], [35, -10], [36, -15], [37, -20], [38, -25], [39, -30], [40, -35], [41, -40], [42, -45], [43, -50]]}
Однако в этом JSON нет места для хранения реквизитов csrfmiddlewaretoken
.
При обращении к документации https://docs.djangoproject.com/en/4.1/ref/csrf/#rejected-requests:
Новое в Django 4.0: Была добавлена проверка происхождения, как описано выше.
похоже, что именно там скрыта ошибка.
Получили следующий JS-код:
function markFunction() {
if (subject_select.value) {
$.ajax({
type: 'POST',
url: '/autocomplete-one-parameter-another-parameter/',
timeout: 3000,
async: true,
tryCount: 0,
retryLimit: 3,
dataType: 'json',
data: {
// Modification Required Here, I suppose >>
id_subject: subject_select.value,
csrfmiddlewaretoken: getCookie('csrftoken')
},
success: function (data) {
if (data) {
var anPt = document.getElementById('id_anotherParameter');
removeOptions(anPt);
var oneParameters = document.getElementById('id_oneParameters');
removeOptions(oneParameters);
var anPtsLength = data['anotherParameters'].length;
console.log("anPtsLength", anPtsLength);
var oneParametersLength = data['oneParameters'].length;
for (var i = 0; i < anPtsLength; i++) {
temp = document.createElement("option");
temp.value = data['anotherParameters'][i][0];
temp.text = data['anotherParameters'][i][1];
anPt.add(temp, null);
}
for (var i = 0; i < oneParametersLength; i++) {
temp = document.createElement("option");
temp.value = data['oneParameters'][i][0];
temp.text = data['oneParameters'][i][1];
oneParameters.add(temp, null);
}
anPt.removeAttribute('disabled');
oneParameters.removeAttribute('disabled');
}
},
error: function(xhr, textStatus, errorThrown) {
}
});
} else {
var anPt = document.getElementById('id_anotherParameter');
removeOptions(anPt);
anPt.setAttribute('disabled', 'disabled');
var oneParameters = document.getElementById('id_oneParameters');
removeOptions(oneParameters);
oneParameters.setAttribute('disabled', 'disabled');
}
}
После некоторых исследований, есть один из двух вариантов, как интегрировать заголовок Origin:
const csrftoken = getCookie('csrftoken');
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
jqXHR.setRequestHeader('X-CSRFToken', csrftoken);
});
или что из Документация:
const request = new Request(
'/autocomplete-one-parameter-another-parameter/',
{
method: 'POST',
headers: {'X-CSRFToken': csrftoken},
mode: 'same-origin' // Do not send CSRF token to another domain.
}
);
fetch(request).then(function(response) {
// ... << Don't understand how to integrate this to the JS above
});
Пожалуйста, может ли кто-нибудь объяснить, какой из вариантов должен быть выбран, и помочь с интеграцией этих двух частей цепи?