简体   繁体   English

Laravel 5.5:进行 AJAX POST 时禁止 403

[英]Laravel 5.5: 403 Forbidden when making AJAX POST

I've been stuck on this for 2 days now, and all the resolutions I looked for on StackOverflow and Laracasts proved inconclusive.我已经被困在这个问题上 2 天了,我在 StackOverflow 和 Laracasts 上寻找的所有解决方案都证明是不确定的。

I am using Laravel 5.5 with jQuery and I do my testing in Firefox.我正在将 Laravel 5.5 与 jQuery 一起使用,并在 Firefox 中进行测试。

My AJAX GET calls are working fine, however, when I try and push an entry in my database, I get a 403 error.我的 AJAX GET 调用工作正常,但是,当我尝试在我的数据库中推送一个条目时,我收到 403 错误。

My header does contain the CSRF token:我的标头确实包含 CSRF 令牌:

<meta name="csrf-token" content="{{ csrf_token() }}">

Models are created for every table called in my controller:为我的控制器中调用的每个表创建模型:

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!']);
    }

Here is the AJAX call, it basically checks for my Quilljs Delta .这是 AJAX 调用,它主要检查我的 Quilljs Delta This Delta is a JSON object formatting a message from WYSIWYG.这个Delta是一个 JSON 对象,用于格式化来自 WYSIWYG 的消息。 Then every 5th second, it should try to push it to my database.然后每 5 秒,它应该尝试将它推送到我的数据库。

I know the Quilljs side works fine because my deltas show properly in my console.我知道 Quilljs 方面工作正常,因为我的 deltas 在我的控制台中正确显示。 But the POST call itself doesn't seem to pass authentication for some reason?但是由于某种原因,POST 调用本身似乎没有通过身份验证? (This is just my guess, to me it seems like the only reason it would send a 403.) (这只是我的猜测,对我来说这似乎是它发送 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);

To make sure the issue didn't come from CSRF, I went a bit overkill and, after trying to set up the token first in ajaxSetup, then in the AJAX data only, I just assigned it in both.为了确保问题不是来自 CSRF,我有点矫枉过正,在尝试首先在 ajaxSetup 中设置令牌后,然后仅在 AJAX 数据中,我只是在两者中分配了它。 None of these scenarios changed anything.这些场景都没有改变任何东西。

Of course, I assigned the 'Web' middleware on my post route to check for the above-mentioned CSRF token.当然,我在我的 post 路由上分配了“Web”中间件来检查上述 CSRF 令牌。 The route I use is as follows:我使用的路线如下:

Route::group(['middleware' => ['web']], function () {
  Route::post('/pushProfile','MessageSend@pushProfile')->name('pushProfile');
});

I also tried to assign the URL as:我还尝试将 URL 分配为:

url: '/pushProfile',

To no avail, unfortunately... This just returns a 404 instead of the 403 I currently have:不幸的是,无济于事......这只是返回一个 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(&quot;pushProfile&quot;) }}\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"
}

Did I miss anything?我错过了什么吗? Thanks!谢谢!

I found the solution, and oh god it was so simple I'm ashamed of myself:我找到了解决方案,天哪,这太简单了,我为自己感到羞耻:

I was calling the AJAX from a .js file, using the blade route.我正在使用刀片路由从 .js 文件调用 AJAX。 Moving the call into a blade file solved the whole issue, as blade routes are only rendered in .blade.php files...将调用移动到刀片文件中解决了整个问题,因为刀片路由仅在 .blade.php 文件中呈现...

I'm leaving the issue out there in case anyone stumbles upon the same trouble :)如果有人偶然发现同样的问题,我将把这个问题留在那里:)

If someone stumbles upon this question and solution keep in mind that if you want to keep your blade templates clean and separate your logic properly into JS files you should create a routes.js file inside your project that holds an object with key-value pairs the same as your named routes in web.php file.如果有人偶然发现这个问题和解决方案,请记住,如果您想保持刀片模板干净并将您的逻辑正确地分离到 JS 文件中,您应该在您的项目中创建一个 routes.js 文件,该文件包含一个带有键值对的对象与 web.php 文件中的命名路由相同。 I suggest placing the file in public/assets/js directory.我建议将文件放在 public/assets/js 目录中。

This way you only have to be mindful when changing your routes to change them in both places.这样,您只需在更改路线时注意在两个地方更改它们。 Example of a routes.js and web.php file in my current project: routes.js我当前项目中的 routes.js 和 web.php 文件示例:routes.js

let routes = {
admDashboard: '/admin',
userOverview: '/admin/users/',
userSearch: '/admin/users/search',
}

web.php网页.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');

And finally the actual usage in an AJAX call:最后是 AJAX 调用中的实际用法:

import routes from '../../routes.js'
function getLatestPosts(callbacksArr) {
$.ajax({
    url: routes['postOverview'],
    type: 'GET',
    dataType: 'json',
    data: '',
    success: callbacksArr
});

} }

The code does not fetch a proper url because '{{ url("/pushProfile") }}' is a Blade syntax and in Laravel 8 the proper way is {{ route('yourNamedRoute') }}.该代码没有获取正确的 url,因为 '{{ url("/pushProfile") }}' 是 Blade 语法,而在 Laravel 8 中正确的方法是 {{ route('yourNamedRoute') }}。 Your AJAX script doesn't know what this is, but a string.您的 AJAX 脚本不知道这是什么,而是一个字符串。 A workaround for using this route with Blade syntax is to use a href and generate from the backend your URL OR put your submission button in a form that has an将此路由与 Blade 语法一起使用的解决方法是使用 href 并从后端生成您的 URL 或将您的提交按钮放在具有

<form action="{{ route('yourNamedRoute') }}"></form>

This way when you call the AJAX function you can prevent the default behavior, grab the url from the action and pass this value by using jQuery:这样,当您调用 AJAX 函数时,您可以防止默认行为,从操作中获取 url 并使用 jQuery 传递此值:

let url = $("#my_form_id").prop('action');
ajaxFunctionThatDoesTheJob(url);

or even force the function to expect an object and allow named arguments like so:甚至强制函数期望一个对象并允许命名参数,如下所示:

function searchPosts({url: url, search: search=null,filter: filter=null, page: page=null,
                     callbacks: callbacksArr, request: request='GET'}) 

then we would call the function like in the example below and pass arbitrary number of arguments:然后我们会像下面的例子一样调用函数并传递任意数量的参数:

ajaxFunctionThatDoesTheJob({url: url});

The benefit of embedding your URL in the form is that you can use CSRF tokens and bunch of other usefull stuff such as method spoofing and hidden input fields.在表单中嵌入你的 URL 的好处是你可以使用 CSRF 令牌和一堆其他有用的东西,比如方法欺骗和隐藏的输入字段。

It took me quite some time to figure this all out so I hope this saves someone a lot of research and helps to write good code :)我花了很长时间才弄清楚这一切,所以我希望这可以为某人节省大量研究并有助于编写好的代码:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM