Laravel 5.5: 403 Forbidden when making AJAX POST
Laravel 5.5: 403 Forbidden when making AJAX POST
我已经坚持了 2 天了,我在 Whosebug 和 Laracasts 上寻找的所有解决方案都没有定论。
我将 Laravel 5.5 与 jQuery 一起使用,并在 Firefox 中进行测试。
我的 AJAX GET 调用工作正常,但是,当我尝试在我的数据库中推送一个条目时,我收到 403 错误。
我的 header 确实包含 CSRF 令牌:
<meta name="csrf-token" content="{{ csrf_token() }}">
为在我的控制器中调用的每个 table 创建模型:
public function pushProfile(Request $request){
$userid = \Auth::user()->id;
$data = $request->message;
$stat = \App\Character::where('owner', $userid)->first();
$mess = \App\Message::firstOrCreate([
'posterID' => $userid,
'loc_x' => '0',
'loc_y' => '0',
'characterID' => $stat->id,
'type' => 'profile'
]);
$mess->content = $data;
$mess->save();
return response()->json(['success'=>'Message has been saved!']);
}
这是 AJAX 调用,它主要检查我的 Quilljs Delta
。此 Delta
是 JSON object 格式化来自所见即所得的消息。然后每隔 5 秒,它应该尝试将其推送到我的数据库。
我知道 Quilljs 端工作正常,因为我的增量在我的控制台中正确显示。但是 POST 调用本身由于某种原因似乎没有通过身份验证? (这只是我的猜测,对我来说这似乎是它发送 403 的唯一原因。)
setInterval(function() {
if (change.length() > 0) {
console.log('Saving changes', change);
/* AJAX setup */
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
headers: {
'Content-Type':'application/json'
},
method: 'POST',
url: '{{ url("/pushProfile") }}',
data: {
message:
{
doc: JSON.stringify(quill.getContents())
},
_token: $('meta[name="csrf-token"]').attr('content')
},
dataType: 'JSON',
error: function(jqXHR, textStatus, errorThrown) {
console.log(JSON.stringify(jqXHR));
console.log("AJAX error: " + textStatus + ' : ' + errorThrown);
},
success: function (data) {
$(".writeinfo").append(data.msg);
console.log("Success!!!");
}
});
change = new Delta();
}
}, 5*1000);
为了确保问题不是来自 CSRF,我有点矫枉过正,在尝试先在 ajaxSetup 中设置令牌之后,然后仅在 AJAX 数据中,我才分配了它同时。 None 这些场景改变了一切。
当然,我在 post 路由上分配了 'Web' 中间件来检查 above-mentioned CSRF 令牌。我使用的路线如下:
Route::group(['middleware' => ['web']], function () {
Route::post('/pushProfile','MessageSend@pushProfile')->name('pushProfile');
});
我还尝试将 URL 分配为:
url: '/pushProfile',
无济于事,不幸的是...这只是 returns 一个 404 而不是我目前拥有的 403:
{
"readyState":4,
"responseText":"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html>
<head>\n<title>403 Forbidden</title>\n</head>
<body>\n<h1>Forbidden</h1>\n
<p>You don't have permission to access
/folder/public/{{ route("pushProfile") }}\n
on this server.<br />\n</p>\n
<hr>\n
<address>Apache/2.4.35 (Win64) PHP/7.2.10 Server at localhost Port 80</address>\n
</body>
</html>\n",
"status":403,
"statusText":"Forbidden"
}
我错过了什么吗?
谢谢!
我找到了解决方案,天啊,太简单了我为自己感到羞耻:
我使用 blade 路由从 .js 文件调用 AJAX。将调用移动到 blade 文件中解决了整个问题,因为 blade 路由仅在 .blade.php 文件中呈现...
我把这个问题留在那里,以防有人遇到同样的问题:)
如果有人偶然发现这个问题和解决方案,请记住,如果您想保持 blade 模板干净并将您的逻辑正确地分离到 JS 文件中,您应该在您的文件中创建一个 routes.js 文件包含 object 和 key-value 对的项目与 web.php 文件中的命名路由相同。我建议将文件放在 public/assets/js 目录中。
这样你只需要在改变路线时注意在两个地方都改变它们。
我当前项目中的 routes.js 和 web.php 文件示例:
routes.js
let routes = {
admDashboard: '/admin',
userOverview: '/admin/users/',
userSearch: '/admin/users/search',
}
web.php
Route::get('/admin', [AdminController::class, 'dashboard'])->name('admDashboard');
// users management
//Route::get('/admin/users/{id}', [AdminController::class,'userDetails'])->name('userDetails'); //noob way
Route::get('admin/users', [UserManagementController::class, 'userOverview'])->name('userOverview'); //proper way - controller expects User obj
Route::get('admin/users/search', [AdminController::class, 'userSearch'])->name('userSearch');
最后是 AJAX 调用中的实际用法:
import routes from '../../routes.js'
function getLatestPosts(callbacksArr) {
$.ajax({
url: routes['postOverview'],
type: 'GET',
dataType: 'json',
data: '',
success: callbacksArr
});
}
代码未获取正确的 url,因为“{{ url("/pushProfile") }}' 是 Blade 语法并且在 Laravel 8 中正确的方法是 {{ route('yourNamedRoute') }}。您的 AJAX 脚本不知道这是什么,而是一个字符串。将此路由与 Blade 语法一起使用的解决方法是使用 href 并从后端生成 URL 或将提交按钮放在具有
的表单中
<form action="{{ route('yourNamedRoute') }}"></form>
这样当您调用 AJAX 函数时,您可以防止默认行为,从操作中获取 url 并使用 jQuery:[=17= 传递此值]
let url = $("#my_form_id").prop('action');
ajaxFunctionThatDoesTheJob(url);
甚至强制函数期望 object 并允许命名参数,如下所示:
function searchPosts({url: url, search: search=null,filter: filter=null, page: page=null,
callbacks: callbacksArr, request: request='GET'})
然后我们将调用下面示例中的函数并传递任意数量的参数:
ajaxFunctionThatDoesTheJob({url: url});
在表单中嵌入 URL 的好处是您可以使用 CSRF 令牌和一堆其他有用的东西,例如方法欺骗和隐藏输入字段。
我花了很长时间才弄清楚这一切,所以我希望这可以节省一些人的大量研究并有助于编写好的代码:)
我已经坚持了 2 天了,我在 Whosebug 和 Laracasts 上寻找的所有解决方案都没有定论。
我将 Laravel 5.5 与 jQuery 一起使用,并在 Firefox 中进行测试。
我的 AJAX GET 调用工作正常,但是,当我尝试在我的数据库中推送一个条目时,我收到 403 错误。
我的 header 确实包含 CSRF 令牌:
<meta name="csrf-token" content="{{ csrf_token() }}">
为在我的控制器中调用的每个 table 创建模型:
public function pushProfile(Request $request){
$userid = \Auth::user()->id;
$data = $request->message;
$stat = \App\Character::where('owner', $userid)->first();
$mess = \App\Message::firstOrCreate([
'posterID' => $userid,
'loc_x' => '0',
'loc_y' => '0',
'characterID' => $stat->id,
'type' => 'profile'
]);
$mess->content = $data;
$mess->save();
return response()->json(['success'=>'Message has been saved!']);
}
这是 AJAX 调用,它主要检查我的 Quilljs Delta
。此 Delta
是 JSON object 格式化来自所见即所得的消息。然后每隔 5 秒,它应该尝试将其推送到我的数据库。
我知道 Quilljs 端工作正常,因为我的增量在我的控制台中正确显示。但是 POST 调用本身由于某种原因似乎没有通过身份验证? (这只是我的猜测,对我来说这似乎是它发送 403 的唯一原因。)
setInterval(function() {
if (change.length() > 0) {
console.log('Saving changes', change);
/* AJAX setup */
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
$.ajax({
headers: {
'Content-Type':'application/json'
},
method: 'POST',
url: '{{ url("/pushProfile") }}',
data: {
message:
{
doc: JSON.stringify(quill.getContents())
},
_token: $('meta[name="csrf-token"]').attr('content')
},
dataType: 'JSON',
error: function(jqXHR, textStatus, errorThrown) {
console.log(JSON.stringify(jqXHR));
console.log("AJAX error: " + textStatus + ' : ' + errorThrown);
},
success: function (data) {
$(".writeinfo").append(data.msg);
console.log("Success!!!");
}
});
change = new Delta();
}
}, 5*1000);
为了确保问题不是来自 CSRF,我有点矫枉过正,在尝试先在 ajaxSetup 中设置令牌之后,然后仅在 AJAX 数据中,我才分配了它同时。 None 这些场景改变了一切。
当然,我在 post 路由上分配了 'Web' 中间件来检查 above-mentioned CSRF 令牌。我使用的路线如下:
Route::group(['middleware' => ['web']], function () {
Route::post('/pushProfile','MessageSend@pushProfile')->name('pushProfile');
});
我还尝试将 URL 分配为:
url: '/pushProfile',
无济于事,不幸的是...这只是 returns 一个 404 而不是我目前拥有的 403:
{
"readyState":4,
"responseText":"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html>
<head>\n<title>403 Forbidden</title>\n</head>
<body>\n<h1>Forbidden</h1>\n
<p>You don't have permission to access
/folder/public/{{ route("pushProfile") }}\n
on this server.<br />\n</p>\n
<hr>\n
<address>Apache/2.4.35 (Win64) PHP/7.2.10 Server at localhost Port 80</address>\n
</body>
</html>\n",
"status":403,
"statusText":"Forbidden"
}
我错过了什么吗? 谢谢!
我找到了解决方案,天啊,太简单了我为自己感到羞耻:
我使用 blade 路由从 .js 文件调用 AJAX。将调用移动到 blade 文件中解决了整个问题,因为 blade 路由仅在 .blade.php 文件中呈现...
我把这个问题留在那里,以防有人遇到同样的问题:)
如果有人偶然发现这个问题和解决方案,请记住,如果您想保持 blade 模板干净并将您的逻辑正确地分离到 JS 文件中,您应该在您的文件中创建一个 routes.js 文件包含 object 和 key-value 对的项目与 web.php 文件中的命名路由相同。我建议将文件放在 public/assets/js 目录中。
这样你只需要在改变路线时注意在两个地方都改变它们。 我当前项目中的 routes.js 和 web.php 文件示例: routes.js
let routes = {
admDashboard: '/admin',
userOverview: '/admin/users/',
userSearch: '/admin/users/search',
}
web.php
Route::get('/admin', [AdminController::class, 'dashboard'])->name('admDashboard');
// users management
//Route::get('/admin/users/{id}', [AdminController::class,'userDetails'])->name('userDetails'); //noob way
Route::get('admin/users', [UserManagementController::class, 'userOverview'])->name('userOverview'); //proper way - controller expects User obj
Route::get('admin/users/search', [AdminController::class, 'userSearch'])->name('userSearch');
最后是 AJAX 调用中的实际用法:
import routes from '../../routes.js'
function getLatestPosts(callbacksArr) {
$.ajax({
url: routes['postOverview'],
type: 'GET',
dataType: 'json',
data: '',
success: callbacksArr
});
}
代码未获取正确的 url,因为“{{ url("/pushProfile") }}' 是 Blade 语法并且在 Laravel 8 中正确的方法是 {{ route('yourNamedRoute') }}。您的 AJAX 脚本不知道这是什么,而是一个字符串。将此路由与 Blade 语法一起使用的解决方法是使用 href 并从后端生成 URL 或将提交按钮放在具有
的表单中<form action="{{ route('yourNamedRoute') }}"></form>
这样当您调用 AJAX 函数时,您可以防止默认行为,从操作中获取 url 并使用 jQuery:[=17= 传递此值]
let url = $("#my_form_id").prop('action');
ajaxFunctionThatDoesTheJob(url);
甚至强制函数期望 object 并允许命名参数,如下所示:
function searchPosts({url: url, search: search=null,filter: filter=null, page: page=null,
callbacks: callbacksArr, request: request='GET'})
然后我们将调用下面示例中的函数并传递任意数量的参数:
ajaxFunctionThatDoesTheJob({url: url});
在表单中嵌入 URL 的好处是您可以使用 CSRF 令牌和一堆其他有用的东西,例如方法欺骗和隐藏输入字段。
我花了很长时间才弄清楚这一切,所以我希望这可以节省一些人的大量研究并有助于编写好的代码:)