laravel-blade - Livewire 服务器返回“405 Method Not Allowed”。在生产中,在开发阶段没有问题
问题描述
我正在使用 TALL 制作的应用程序。在本地工作正常,在生产一页 3 个表单上,得到错误“405 Method Not Allowed”
错误跟踪显示 POST 方法而不是 GET 方法存在问题。
该表格是三种表格的混合。1- 有个人资料的那个 2. 有密码的那个 3. 有令牌的那个
这三种形式都是 livewire 的组成部分。
每个人都有自己的按钮,要保存。
因此,错误发生在生产中的三个保存按钮中的任何一个中。
wep.php
Route::group(['prefix' => 'dashboard', 'as' => 'admin.', 'middleware' => ['auth']], function () {
...
Route::get('/profile', Profile::class)->name('profile');
...
}
配置文件.php
<?php
namespace App\Http\Livewire\Auth;
use App\Models\User;
use Livewire\Component;
class Profile extends Component
{
public User $user;
public function mount() { $this->user = auth()->user(); }
public function render()
{
return view('livewire.auth.profile');
}
}
更新密码.php
<?php
namespace App\Http\Livewire\Auth\Profile;
use Livewire\Component;
use App\Models\User;
class UpdatePassword extends Component
{
//public User $user;
public $password;
public $password_confirmation;
public function render()
{
return view('livewire.auth.profile.update-password');
}
protected $rules = [
'password' => [
'required',
'confirmed',
'min:10',
'regex:/^.*(?=.{3,})(?=.*[a-zA-Z])(?=.*[0-9])(?=.*[\d\x])(?=.*[!$#%]).*$/',
],
];
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
public function save()
{
$this->validate();
auth()->user()->update([
'password' => bcrypt($this->password)
]);
$this->emitSelf('notify-saved');
$this->resetForm();
}
protected function resetForm()
{
$this->password = '';
$this->password_confirmation = '';
}
}
更新配置文件.php
<?php
namespace App\Http\Livewire\Auth\Profile;
use App\Models\User;
use Livewire\Component;
use Livewire\WithFileUploads;
class UpdateProfile extends Component
{
use WithFileUploads;
public User $user;
public $upload;
public function render()
{
return view('livewire.auth.profile.update-profile');
}
protected function rules(): array
{
return [
'user.name' => [
'string',
'required',
'min:5',
],
'user.email' => [
'email:rfc',
'required',
'regex:/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/ix',
'unique:users,email,' . $this->user->id,
],
'upload' => [
'nullable',
'image',
'mimes:jpg,bmp,png',
'max:200'
],
];
}
public function mount() { $this->user = auth()->user(); }
public function save()
{
$this->validate();
$this->user->save();
$this->upload && $this->user->update([
'avatar' => $this->upload->store('/', 'avatars'),
]);
$this->emitSelf('notify-saved');
}
}
更新令牌.php
<?php
namespace App\Http\Livewire\Auth\Profile;
use App\Helpers\ApiHelpers;
use Livewire\Component;
class UpdateToken extends Component
{
public string $token;
public function mount()
{
$this->resetState();
}
public function updateToken()
{
$user = auth()->user();
ApiHelpers::deleteTokenUserType($user->id, 'auth_token');
$this->token = auth()->user()->createToken('auth_token')->plainTextToken;
}
public function render()
{
return view('livewire.auth.profile.update-token');
}
protected function resetState()
{
$this->token = '';
}
}
profile.blade.php
<div>
@livewire('auth.profile.update-profile')
<!-- Contraseña -->
<div class="hidden sm:block" aria-hidden="true">
<div class="py-5">
<div class="border-t border-gray-200"></div>
</div>
</div>
@livewire('auth.profile.update-password')
<!-- Token -->
<div class="hidden sm:block" aria-hidden="true">
<div class="py-5">
<div class="border-t border-gray-200"></div>
</div>
</div>
@livewire('auth.profile.update-token')
</div>
更新profile.blade.php
<div>
<div class="md:grid md:grid-cols-3 md:gap-6 border-gray-300">
<div class="md:col-span-1">
<h3 class="text-lg font-medium leading-6 text-gray-900">Perfil</h3>
<p class="mt-1 text-sm text-gray-500">
Esta información es privada y sólo tiene efectos administrativos.
</p>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form wire:submit.prevent="save">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<div class="px-4 py-5 bg-white space-y-6 sm:p-6">
<!-- Nombre -->
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="name" class="block text-sm font-medium text-gray-700">
Nombre
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model.defer="user.name" type="text" name="username" id="username" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300" placeholder="Nombre y apellidos">
</div>
<div class="mt-1 relative rounded-md shadow-sm">
@error('user.name')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
@enderror
</div>
</div>
</div>
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="email" class="block text-sm font-medium text-gray-700">
Email
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model.defer="user.email" type="text" name="email" id="email" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300" placeholder="Correo electrónico">
</div>
<div class="mt-1 relative rounded-md shadow-sm">
@error('user.email')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
@enderror
</div>
</div>
</div>
<div>
<label class="block text-sm font-medium text-gray-700">
Foto
</label>
<div class="mt-1 flex items-center space-x-5">
<span class="inline-block h-12 w-12 rounded-full overflow-hidden bg-gray-100">
@if ($upload)
<img src="{{ $upload->temporaryUrl() }}" alt="Profile Photo">
@else
<img src="{{ auth()->user()->avatarUrl() }}" alt="Profile Photo">
@endif
</span>
<input type="file" wire:model="upload" id="photo">
<div class="mt-1 relative rounded-md shadow-sm">
@error('user.avatar')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
@enderror
</div>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Save
</button>
<span x-data="{ open: false }"
x-init="@this.on('notify-saved',
() => {
if (open === false) setTimeout(() => { open = false }, 3500);
open = true;
})"
x-show.transition.out.duration.1000ms="open"
style="display: none;"
class="text-gray-500">¡Guardado!</span>
</div>
</div>
</form>
</div>
</div>
</div>
更新密码.blade.php
<div>
<div class="md:grid md:grid-cols-3 md:gap-6 border-gray-300">
<div class="md:col-span-1">
<h3 class="text-lg font-medium leading-6 text-gray-900">Contraseña</h3>
<p class="mt-1 text-sm text-gray-500">
Puede cambiar su contraseña en este formulario
</p>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form wire:submit.prevent="save">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<div class="px-4 py-5 bg-white space-y-6 sm:p-6">
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="password" class="block text-sm font-medium text-gray-700">
Contraseña
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model.defer="password" type="password" name="password" id="password" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300" placeholder="Nueva contraseña">
</div>
<div class="mt-1 relative rounded-md shadow-sm">
@error('password')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
@enderror
</div>
</div>
</div>
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="password_confirmation" class="block text-sm font-medium text-gray-700">
Confirma la contraseña
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model.defer="password_confirmation" type="password" name="password_confirmation" id="password_confirmation" class="focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300">
</div>
<div class="mt-1 relative rounded-md shadow-sm">
@error('password_confirmation')
<div class="mt-1 text-red-500 text-sm">{{ $message }}</div>
@enderror
</div>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Cambiar
</button>
<span x-data="{ open: false }"
x-init="@this.on('notify-saved',
() => {
if (open === false) setTimeout(() => { open = false }, 3500);
open = true;
})"
x-show.transition.out.duration.1000ms="open"
style="display: none;"
class="text-gray-500">¡Contraseña cambiada!
</span>
</div>
</div>
</form>
</div>
</div>
</div>
更新令牌.php
<div>
<div class="md:grid md:grid-cols-3 md:gap-6 border-gray-300">
<div class="md:col-span-1">
<h3 class="text-lg font-medium leading-6 text-gray-900">Token API</h3>
<p class="mt-1 text-sm text-gray-500">
El token solo se muestra una vez generado, por seguridad.
<br />Copielo y guardelo en un lugar seguro.
<br />El anterior se elimina del sistema, dejan de ser operativo.
</p>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<form wire:submit.prevent="updateToken">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<div class="px-4 py-5 bg-white space-y-6 sm:p-6">
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="token" class="block text-sm font-medium text-gray-700">
Token
</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input wire:model="token" type="text" name="token" id="token" disabled class="disabled:opacity-50 focus:ring-indigo-500 focus:border-indigo-500 flex-1 block w-full rounded-none rounded-r-md sm:text-sm border-gray-300" placeholder="Haz click en el botón para regenerar el token">
</div>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Regenerar
</button>
</div>
</div>
</form>
</div>
</div>
</div>
解决方案
一个不可原谅的错误。
作为系统管理员,我忘记了您必须查看日志。其中还有 mod_security 日志。
--9ac02665-F--
HTTP/1.1 405 Method Not Allowed
allow: POST
Cache-Control: no-cache, private
date: Fri, 12 Nov 2021 15:18:31 GMT
Connection: close
Content-Type: text/html; charset=UTF-8
Server: Apache
--9ac02665-H--
Message: Warning. Matched phrase ".profile" at REQUEST_FILENAME. [file "/etc/apache2/conf.d/modsec_vendor_configs/OWASP3/rules/REQUEST-930-APPLICATION-ATTACK-LFI.conf"] [line "124"] [id "930130"] [msg "Restricted File Access Attempt"] [data "Matched Data: .profile found within REQUEST_FILENAME: /livewire/message/auth.profile.update-profile"] [severity "CRITICAL"] [ver "OWASP_CRS/3.3.2"] [tag "application-multi"] [tag "language-multi"] [tag "platform-multi"] [tag "attack-lfi"] [tag "paranoia-level/1"] [tag "OWASP_CRS"] [tag "capec/1000/255/153/126"] [tag "PCI/6.5.4"]
推荐阅读
- javascript - 从选择框数组中获取数据属性
- javascript - WordPress 中的 Wistia 视频在内容中加载额外的脚本和脚本标签
- firebase - 在只有两个用户的测试环境中达到 100 个活动连接限制
- linux - 无法在 I2C 设备上使用 write() 或 read() 调用,但 echo 和 i2c-tools 工作
- node.js - 在 AJAX 请求上更新 EJS 变量
- c++ - 将一种类型的位重新解释为不同类型的技术
- javascript - 在laravel中通过ajax删除数据
- vim - Vim 查找和替换时间 hh:mm
- javascript - 是否可以仅在 JavaScript 中制作按钮?
- php - 自动加载一个php文件,它是jquery Ajax方法的url