Laravel 5.5:进行AJAX POST时禁止使用403

时间:2018-11-07 13:21:00

标签: jquery ajax laravel-5.5

我已经坚持了两天,事实证明,我在StackOverflow和Laracasts上寻求的所有解决方案都没有定论。

我正在将Laravel 5.5与jQuery一起使用,并在Firefox中进行了测试。

我的AJAX GET调用工作正常,但是,当我尝试在数据库中推送条目时,出现403错误。

我的标头确实包含CSRF令牌:

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

为控制器中调用的每个表创建模型:

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 DeltaDelta是一个JSON对象,用于格式化来自所见即所得的消息。然后每隔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数据中设置令牌后,我才在两个中都分配了令牌。这些情况都没有改变任何东西。

当然,我在发布路线上分配了“ Web”中间件,以检查上述CSRF令牌。我使用的路线如下:

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

我还尝试将URL分配为:

url: '/pushProfile',

不幸的是,这无济于事……这只会返回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"
}

我错过了什么吗? 谢谢!

2 个答案:

答案 0 :(得分:1)

我找到了解决方案,哦,天哪太简单了,我为自己感到羞耻:

我使用刀片路由从.js文件中调用AJAX。将呼叫转移到刀片文件中解决了整个问题,因为刀片路由仅在.blade.php文件中呈现...

如果有人遇到同样的麻烦,我会把问题留在那儿:)

答案 1 :(得分:0)

如果有人偶然发现了这个问题和解决方案,请记住,如果您想保持刀片模板干净并将您的逻辑正确地分离到 JS 文件中,您应该在项目中创建一个 routes.js 文件,其中包含一个带有键的对象 -值对与 web.php 文件中的命名路由相同。我建议将文件放在 public/assets/js 目录中。

这样,您只需在更改路线时注意即可在两个地方更改它们。 我当前项目中的 routes.js 和 web.php 文件示例: 路由.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 传递此值:

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

甚至强制函数期待一个对象并允许像这样命名参数:

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

然后我们会像下面的例子一样调用函数并传递任意数量的参数:

ajaxFunctionThatDoesTheJob({url: url});

在表单中嵌入 URL 的好处是您可以使用 CSRF 令牌和一堆其他有用的东西,例如方法欺骗和隐藏输入字段。

我花了很长时间才弄清楚这一切,所以我希望这可以为某人节省大量研究并有助于编写好的代码:)