Как передать токен CSRF в запросе AJAX post для формы?

Я использую Scala Play! 2.6 основы, но это не может быть проблемой. Я использую их маршрутизацию Javascript - и, похоже, она работает нормально, но у нее проблемы. У меня есть форма, которая при рендеринге производит это, с токеном CSRF:

<form method="post" id="myForm" action="someURL">

<input name="csrfToken" value="5965f0d244b7d32b334eff840...etc" type="hidden">
  <input type="text" id="sometext">
  <button type="submit"> Submit! </button>

</form>

и вот, примерно, мой Аякс:

$(document).on('submit', '#myForm', function (event) {

 event.preventDefault();
   var data = {
    textvalue: $('#sometext').val()
   }
 var route = jsRoutes.controllers.DashboardController.postNewProject()
 $.ajax({
    url: route.url,
    type: route.type,
    data : JSON.stringify(data),
    contentType : 'application/json',
    success: function (data) { ...      },
    error: function (data) { ...  }
        })

});

но когда я публикую это, я получаю несанкционированный ответ с моего сервера, и моя консоль в IntelliJ говорит мне, что проверка CSRF не выполняется. Как бы я прошел по CSRF токен в запросе?

5 ответов


хорошо, после борьбы с этим в течение нескольких часов и попытки расшифровать часто отсутствующую контекстную документацию Play на теме, я понял.

Итак, из их документов:

чтобы обеспечить простую защиту для не запросов браузера, играть только проверки запросы с cookies в заголовке. Если вы делаете запросы с AJAX, вы можете разместить токен CSRF на странице HTML, а затем добавить его на запрос с помощью Csrf-Token заголовок.

и тогда нет кода или примера. Спасибо Играть. Очень описательно. Во всяком случае, вот так:

в своем view.html.formTemplate вы можете написать в IntelliJ:

@()
<form method="post" id="myForm" action="someURL">

@helper.CSRF.formField  <!-- This auto-generates a token for you -->
  <input type="text" id="sometext">
  <button type="submit"> Submit! </button>

</form>

и это будет отображаться следующим образом при доставке клиенту:

<form method="post" id="myForm" action="someURL">

<input name="csrfToken" value="5965f0d244b7d32b334eff840...etc" type="hidden">
  <input type="text" id="sometext">
  <button type="submit"> Submit! </button>

</form>

ОК, почти там, теперь мы должны создать наш вызов AJAX. У меня все свои в отдельной магистрали.JS-файл, но вы также можете поместить это в свой view.html.formTemplate если вы хотеть.

$(document).on('submit', '#myForm', function (event) {

 event.preventDefault();
   var data = {
    myTextToPass: $('#sometext').val()
   }
 // LOOK AT ME! BETWEEN HERE AND
 var token =  $('input[name="csrfToken"]').attr('value')
    $.ajaxSetup({
        beforeSend: function(xhr) {
            xhr.setRequestHeader('Csrf-Token', token);
        }
    });
// HERE
 var route = jsRoutes.controllers.DashboardController.postNewProject()
 $.ajax({
    url: route.url,
    type: route.type,
    data : JSON.stringify(data),
    contentType : 'application/json',
    success: function (data) { ...      },
    error: function (data) { ...  }
        })

});

С этой линии: var token = $('input[name="csrfToken"]').attr('value') Вы вырываете токен CSRF, автоматически созданный в поле формы, и захватываете его значение в var, который будет использоваться в вашем Javascript.

другой важный кусок из всего, что AJAX здесь:

$.ajaxSetup({
            beforeSend: function(xhr) {
                xhr.setRequestHeader('Csrf-Token', token);
            }
        });

С помощью $.ajaxSetup вы можете указать, что в заголовке. Это то, что вы должны сделать из своей документации:

добавьте его в запрос с помощью Csrf-токена заголовок.

удачи! Дай мне знать, если все ясно.


Примечание при использовании lusca используйте X-CSRF-Token вместо Csrf-Token.


добавьте его в запрос, используя Csrf-Token заголовок.

спасибо NateH06 название заголовка! Я пытался отправить токен csrf для кнопки "удалить" с вызовом функции ajax, и я застрял на следующем:

@import helper._
....
<button id="deleteBookBtn" class="btn btn-danger"
        data-csrf-name="@helper.CSRF.getToken.name"
        data-csrf-value="@helper.CSRF.getToken.value"
        data-delete-url="@routes.BooksController.destroy(book.id)"
        data-redirect-url="@routes.HomeController.index()">Delete</button>

Я не смог добавить онлайн js в onclick() событие из-за CSP, установленного на play 2.6 тоже.

отказался выполнять встроенный обработчик событий, поскольку он нарушает следующее содержимое Директива политики безопасности: "default-src 'self'".

и в файле JS:

function sendDeleteRequest(event) {
  url = event.target.getAttribute("data-delete-url")
  redirect = event.target.getAttribute("data-redirect-url")
  csrfTokenName = event.target.getAttribute("data-csrf-name")
  csrfTokenValue = event.target.getAttribute("data-csrf-value")
  $.ajax({
    url: url,
    method: "DELETE",
    beforeSend: function(request) {
      //'Csrf-Token' is the expected header name, not $csrfTokenName
      request.setRequestHeader(/*$csrfTokenName*/'Csrf-Token', csrfTokenValue);
    },
    success: function() {
      window.location = redirect;
    },
    error: function() {
      window.location.reload();
    }
  })
}

var deleteBookBtn = document.getElementById("deleteBookBtn");
if(deleteBookBtn) {
    deleteBookBtn.addEventListener("click", sendDeleteRequest);
}

после установки имени заголовка как 'Csrf-Token' вызов ajax работает отлично!


от JSP

<form method="post" id="myForm" action="someURL">
    <input name="csrfToken" value="5965f0d244b7d32b334eff840...etc" type="hidden">    
</form>

Это самый простой способ, который работал для меня после борьбы за 3hrs, просто получите токен из скрытого поля ввода, как это, и при выполнении запроса AJAX просто нужно передать этот токен в заголовке следующим образом: -

В JQuery

var token =  $('input[name="csrfToken"]').attr('value'); 

из простого Javascript

var token = document.getElementsByName("csrfToken").value;

окончательный запрос AJAX

$.ajax({
      url: route.url,
      data : JSON.stringify(data),
      method : 'POST',
      headers: {
                    'X-CSRF-Token': token 
               },
      success: function (data) { ...      },
      error: function (data) { ...  }

});

теперь вам не нужно отключать безопасность crsf в web config, и также это не даст вам ошибку 405( метод не разрешен) на консоли.

надеюсь, это поможет людям..!!


вы можете добавить Csrf-Token заголовок .

$.ajax({
    url: '@routes.MyController.myPostAction()',
    method: 'post',
    headers: {
        'Csrf-Token': '@play.filters.csrf.CSRF.getToken.map(_.value)'
    },
    data: {
        name: '@name'
    },
    success: function (data, textStatus, jqXHR) {
        location.reload();
    },
    error: function (jqXHR, textStatus, errorThrown) {
        debugger;
    }
});

как говорится в Play Framework 2.6 Документация, вы можете установить 'Csrf-Token' заголовок с токеном, генерируемым Play:

если вы делаете запросы с AJAX, вы можете разместить токен CSRF на странице HTML, а затем добавить его в запрос с помощью Csrf-Token заголовок.

в шаблоне Scala вы можете получить значение токена, используя @helper.CSRF.getToken.value

после документация jQuerys вы можете либо установить его один раз для всех запросов Ajax, настроив jQuery с помощью метода ajaxsetup

$.ajaxSetup({
  beforeSend: function(xhr) {
    xhr.setRequestHeader('Csrf-Token', '@helper.CSRF.getToken.value');
  }
});

или альтернативно установите заголовок для каждого запроса, настроив headers объект вроде этого:

$.ajax({
  url: route.url,
  ...
  headers: {
    'Csrf-Token': '@helper.CSRF.getToken.value'
  }
});