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
});

Пожалуйста, может ли кто-нибудь объяснить, какой из вариантов должен быть выбран, и помочь с интеграцией этих двух частей цепи?

Вернуться на верх