jQuery将CSRF令牌添加到所有$ .post()请求的数据中
我正在开发一个Laravel 5应用程序,该应用程序默认为所有POST请求启用CSRF保护。 我喜欢这个增加的安全性所以我正在尝试使用它。
在进行简单的$.post()
请求时,我收到了'Illuminate\Session\TokenMismatchException'
错误,因为POST数据中缺少所需的表单输入_token
。 以下是有问题的$ .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');
是否可以将此附加到所有传出$.post()
请求的json数据? 我尝试使用标题,但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); } });
你的$.ajaxPrefilter
方法很好。 但是,您不需要添加标题; 您只需要向data
字符串添加属性。
数据作为$.post
的第二个参数提供,然后在预filter访问data
选项之前格式化为查询字符串( id=foo&bar=baz&...
)。 因此,您需要将自己的字段添加到查询字符串:
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
。
来自Laravel文档:
例如,您可以将令牌存储在“meta”标记中:
创建元标记后,您可以指示像jQuery这样的库将标记添加到所有请求标头。 这为基于AJAX的应用程序提供了简单,方便的CSRF保护:
$ .ajaxSetup({headers:{‘X-CSRF-TOKEN’:$(’meta [name =“csrf-token”]’)。attr(’content’)}});
例如,您可以像下面那样提出要求。
将此元标记添加到您的视图中:
这是一个示例脚本,您可以与Laravel进行通信(当您单击id =“some-id”的元素时发送请求,您可以在id =“result”的元素中看到响应):
一般来说,我同意Kornel建议的概念,除了一件事。
是的,Laravel的文档建议使用$.ajaxSetup
,但不建议这样$.ajaxSetup
,因为此方法会影响所有后续的ajax请求。 为每个请求设置ajax设置更为正确。 虽然你可以重新设置东西:
使用任何函数的所有后续Ajax调用都将使用新设置,除非被单个调用覆盖,直到下一次调用$ .ajaxSetup()
如果使用$.ajax()
,则使用data
属性或headers
更方便。 Laravel允许CSRF令牌作为请求参数或标头。
首先,在视图中添加以下元标记
然后以任何一种方式发出ajax请求:
$.ajax({ url: "/your/url", method: "POST", data: { a: 'something', b: 'something else', _token: $('meta[name="csrf-token"]').attr('content') }, datatype: "json" });
要么
$.ajax({ url: "/your/url", method: "POST", data: { a: 'something', b: 'something else', }, headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } datatype: "json" });
关于CSRF的Django文档提供了一个带有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); } } });
我认为上述解决方案可能效果不佳。 当你这样做时:
var x; x + "" // "undefined" + empty string coerces value to string
你会得到像“undefined_token = xxx”这样的数据
例如,当您使用上述解决方案进行laravel的删除时,您必须像这样检查:
if (typeof options.data === "undefined") options.data = ""; else options.data += "&"; options.data = "_token=" + csrf_token;
有一个更容易的方法来执行此操作,您可以在发送之前序列化数据
具有名称attr的所有内容都将被放入查询并提交