laravel 403文件上传时收到禁止的错误

yvt65v4c  于 2023-01-31  发布在  其他
关注(0)|答案(3)|浏览(158)

bounty将在2天后过期。回答此问题可获得+500声望奖励。farjam希望引起更多人关注此问题。

我尝试在我的Laravel 9应用程序中上传一个文件。在本地主机上,它运行得很好,但是,当我尝试在Amazon Linux EC2上运行我的应用程序时,同样的操作失败了。

我所知道的

  • 这个动作不会抛出任何异常,它只会收到一个HTTP 403错误。(我已经在我的.env中启用了调试)
  • 我只在尝试上传图像的地方收到这个错误。其他控制器工作正常。
    我怀疑问题是:
  • 我认为问题出在Apache/服务器配置上。我在update()函数的第一行添加了一个dd()调用,但它甚至没有到达那里。在此之前抛出了403错误。见下文。
    我为排除故障所做的工作:
  • 已确保S3存储桶策略正常(同一控制器在本地主机上工作正常)
  • 已确保文件权限正常(请参见下面的屏幕截图)
  • 确保request类中的authorize()函数返回true
  • 我查看了错误日志,也没有发现任何相关内容。
  • 已确保php.ini中包含file_uploads = Onupload_max_filesize = 4Mmax_file_uploads = 20

我的控制器如下所示(UpdateContactRequest中的authorize()函数返回true):

//https://myapp.com/contacts/1
    //App\Http\Controllers\ContactController
    public function update(UpdateContactRequest $request, Contact $contact)
    {
        dd($request); //This does not get executed. The 403 error happens before reaching this. 

        $contact->update($request->all());

        $this->uploadAvatar($request, $contact);

        Flash::success('Contact updated successfully.');

        return redirect(route('dealers.contacts.index', $contact->dealer->id));
    }

下面是我用来上传的uploadAvatar函数:

private function uploadAvatar(Request $request, Contact $contact)
    {
        if ($request->hasFile('avatar')) {
            try {
                $contact
                    ->addMediaFromRequest('avatar')
                    ->sanitizingFileName(function ($fileName) {
                        return strtolower(str_replace(['#', '/', '\\', ' '], '-', $fileName));
                })
                ->toMediaCollection('avatars');
            } catch (\Spatie\MediaLibrary\MediaCollections\Exceptions\FileUnacceptableForCollection $e) {
                Flash::error($e->getMessage());
            }
        }
    }

如何定义路由:

Route::get('/', function () {
    return view('welcome');
});

Route::get('/test', App\Http\Controllers\TestController::class);
Route::get('/embed-iframe/{uuid}', [App\Http\Controllers\EmbedController::class, 'iframe']);
Route::get('/embed-js/{uuid}', [App\Http\Controllers\EmbedController::class, 'js']);
Auth::routes();

Route::middleware('admin')->group(function () {
    Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
    Route::resource('dealers', App\Http\Controllers\DealerController::class);
    Route::post('refreshDealerCRMData', [App\Http\Controllers\DealerController::class, 'refreshCRMData']);
    Route::post('loadCRMView', [App\Http\Controllers\DealerController::class, 'loadCRMView']);
    Route::resource('cms', App\Http\Controllers\CmsController::class);
    Route::resource('crms', App\Http\Controllers\CrmController::class);
    Route::resource('leads', App\Http\Controllers\LeadController::class);
    Route::resource('contacts', App\Http\Controllers\ContactController::class);
    Route::resource('attachment-categories', App\Http\Controllers\AttachmentCategoryController::class);
    Route::resource('CRMAttachments', App\Http\Controllers\CRMAttachmentController::class);
    Route::resource('dealers.leads', App\Http\Controllers\DealerLeadController::class)->scoped([
        'dealers' => 'dealer.id',
        'leads' => 'lead.id',
    ]);
    Route::resource('dealers.contacts', App\Http\Controllers\DealerContactController::class)->scoped([
        'dealers' => 'dealer.id',
        'contacts' => 'contact.id',
    ]);
});

下面是我的根目录(/var/www/html)的屏幕截图:

下面是在/etc/httpd/conf/httpd.conf中定义的虚拟主机

<VirtualHost *:443>
 ServerAdmin user@domain.com
 ServerName myapp.com
 ServerAlias www.myapp.com
 DocumentRoot /var/www/html/public
 <Directory /var/www/html>
  Options Indexes FollowSymLinks MultiViews
  AllowOverride All
  Require all granted
 </Directory>
</VirtualHost>

<VirtualHost *:80>
  ServerAdmin user@domain.com
  ServerName myapp.com
  ServerAlias www.myapp.com
  DocumentRoot /var/www/html/public
  <Directory /var/www/html>
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    Require all granted
  </Directory>
</VirtualHost>

以下是我的IAM策略:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::mybucket",
                "arn:aws:s3:::mybucket/*"
            ]
        }
    ]
}

下面是抛出的确切错误的屏幕截图:

在没有抛出实际异常的情况下,如何进一步解决这个问题?

mbskvtky

mbskvtky1#

此问题与AWS WAF规则有关,该规则阻止HTTP发布大小超过特定数字。已删除该规则,现在它可以正常工作。

ia2d9nvy

ia2d9nvy2#

对于其他使用AWS遇到神秘的403错误的用户,这里有一个调试这个问题和类似问题的方法。
首先,验证您的请求是否命中了您的应用程序。一个很好的方法是尝试在AppServiceProvider中执行dd()。在这种情况下,它不会返回任何内容,这就是它位于应用程序外部的线索。如果它位于应用程序内部,请使用dd()通过应用程序继续调试,或者登录Laravel日志。
下一步是确保您正在访问服务器-使用AWS时有两种方法。

使用抽样请求视图

AWS对viewing a sample of web requests有一个彻底的演练-这将允许您查看AWS WAF检查过的任何传入请求,以及允许或阻止的请求。

AWS Waf日志

此外,在设置新项目时,我建议始终启用AWS Waf Logs,这样您就可以看到哪个规则是阻止请求的终止规则。
这两种方法应该足以调试此类错误。

6ju8rftf

6ju8rftf3#

我猜你遇到的403问题是在一个共享主机中发生的.当你用php artisan storage:link创建符号链接时,它包含了storage/app/public文件夹的完整绝对路径.这可能是服务器响应403的原因.
解决方案是创建一个符号链接,其相对路径与项目根类似
ln -s../存储/应用程序/公共公共/存储

相关问题