JQuery добавляет токен CSRF ко всем данным запросов $ .post ()
Автор вопроса: NightMICUОтветов: 7
Я работаю над приложением Laravel 5, в котором по умолчанию включена защита CSRF для всех запросов POST. Мне нравится эта дополнительная безопасность, поэтому я пытаюсь с ней работать.
При выполнении простого $.post() запроса я получил 'Illuminate\Session\TokenMismatchException' ошибку, потому что требуемый ввод формы _token отсутствовал в данных POST. Вот пример рассматриваемого запроса $ .post:
var userID = $("#userID").val();
$.post('/admin/users/delete-user', {id:userID}, function() {
// User deleted
});
У меня есть токен CSRF, который хранится как мета-поле в моем заголовке, и я могу легко получить к нему доступ, используя:
var csrf_token = $('meta[name="csrf-token"]').attr('content');
Можно ли добавить это к данным json для всех исходящих $.post() запросов? Я пробовал использовать заголовки, но Laravel, похоже, их не распознал -
var csrf_token = $('meta[name="csrf-token"]').attr('content');
alert(csrf_token);
$.ajaxPrefilter(function(options, originalOptions, jqXHR){
if (options['type'].toLowerCase() === "post") {
jqXHR.setRequestHeader('X-CSRFToken', csrf_token);
}
});
Правильно ли я понимаю, что вы хотите, чтобы в вашем объекте данных было поле _token? (например, что-то вроде options['data']._token = csrf_token?) Один пример рабочего запроса был бы полезен, если он у вас есть. apsillers 09.02.2015
Чтобы запрос работал, мне пришлось бы добавить токен непосредственно в данные сообщения - так {id:userID, '_token':token} NightMICU 09.02.2015
Итак, вы в основном ответили в комментарии выше, но это не подходящее решение - options['data']._token = csrf_token;, похоже, не выполняет свою работу, но закрывается. Отправьте рабочий ответ, и вы получите +1 и принятый ответ. :) NightMICU 09.02.2015
Отметьте этот ответ - stackoverflow.com/questions/53684928/ Prateek 22.12.2018
Ваш $.ajaxPrefilter подход хорош. Однако вам не нужно добавлять заголовок; вам просто нужно добавить свойство в строку data.
Данные предоставляются в качестве второго аргумента для $.post, а затем форматируются как строка запроса (id=foo&bar=baz&...) до того, как предварительный фильтр получит доступ к параметру data. Таким образом, вам нужно добавить в строку запроса собственное поле:
var csrf_token = $('meta[name="csrf-token"]').attr('content');
$.ajaxPrefilter(function(options, originalOptions, jqXHR){
if (options.type.toLowerCase() === "post") {
// initialize `data` to empty string if it does not exist
options.data = options.data || "";
// add leading ampersand if `data` is non-empty
options.data += options.data?"&":"";
// add _token entry
options.data += "_token=" + encodeURIComponent(csrf_token);
}
});
Это превратит id=userID в id=userID&_token=csrf_token.
Ответ 2 · рейтинг 35 · Kornel
Из документации Laravel:
Вы можете, например, сохранить токен в "метатеге":
Once you have created the meta tag, you can instruct a library like
jQuery to add the token to all request headers. This provides simple,
convenient CSRF protection for your AJAX based applications:
И это пример сценария, с которым вы можете взаимодействовать с Laravel (отправляет запрос, когда вы щелкаете элемент с id = "some-id", и вы можете увидеть ответ в элементе с id = "result"):
В целом я согласен с концепцией, предложенной Корнелем, за исключением одного момента.
Да, в документации Laravel рекомендуется использовать $.ajaxSetup, но это не рекомендуется, поскольку этот метод влияет на все последующие запросы ajax. Правильнее выставлять настройки ajax для каждого запроса. Хотя вы можете переустановить вещи:
Все последующие вызовы Ajax с использованием любой функции будут использовать новые настройки, если они не будут отменены отдельными вызовами, до следующего вызова $ .ajaxSetup ()
Если вы используете $.ajax(), удобнее использовать свойство data или headers. Laravel допускает использование CSRF-токена как в качестве параметра запроса, так и в качестве заголовка.
Сначала вы добавляете в представление следующий метатег
Документация Django по CSRF дает хороший фрагмент кода с ajaxSetup для автоматического добавления соответствующего заголовка ко всем типам запросов, где это важно:
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
Ответ 5 · Kamil Latosinski
Я думаю, что приведенное выше решение может не сработать. Когда вы это сделаете:
var x;
x + ""
// "undefined" + empty string coerces value to string
Вы получите такие данные, как "undefined_token = xxx".
Когда вы используете вышеуказанное решение для удаления laravel, например, вы должны проверить следующее:
все с именем attr будет помещено в запрос и отправлено
Ответ 7 · Amir Keramat
нет необходимости устанавливать какой-либо метатег, ни csrf_token (), ни csrf_field ()!
Вы можете использовать этот фрагмент jQuery:
$.ajaxPrefilter(function( settings, original, xhr ) {
if (['post','put','delete'].includes(settings.type.toLowerCase())
&& !settings.crossDomain) {
xhr.setRequestHeader("X-XSRF-TOKEN", getCookie('XSRF-TOKEN'));
}
});
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 = jQuery.trim(cookies[i]);
// 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;
}
несколько других ответов пытались установить заголовок csrf, но в соответствии с документами Laravel (здесь), ключ заголовка должен быть "X-XSRF-TOKEN", а сам Laravel предоставляет необходимое значение при каждом запросе для нас в файле cookie с именем "XSRF-TOKEN"
так что просто исправил ключи и отредактировал несколько строк, спасибо