Skip to content
全部文档

Locked

#[Locked] 属性阻止属性在客户端被修改,保护模型 ID 等敏感数据不被用户篡改。

基本用法

#[Locked] 属性应用到任何不应从前端更改的公共属性上:

php
<?php // resources/views/components/post/⚡show.blade.php

use Livewire\Attributes\Locked;
use Livewire\Component;
use App\Models\Post;

new class extends Component {
    #[Locked] // [tl! highlight]
    public $postId;

    public function mount($id)
    {
        $this->postId = $id;
    }

    public function delete()
    {
        Post::find($this->postId)->delete();

        return redirect('/posts');
    }
};

若用户试图通过浏览器开发者工具或篡改请求来修改被锁定的属性,Livewire 将抛出异常并阻止操作执行。

WARNING

后端修改仍然允许

带有 #[Locked] 属性的属性仍可在组件的 PHP 代码中修改。锁定仅防止客户端篡改。请注意不要在自己的方法中将不可信的用户输入传给被锁定的属性。

何时使用

在以下情况使用 #[Locked]

  • 存储绝不应被用户更改的模型 ID
  • 在整个组件生命周期中保留与授权相关的敏感数据
  • 保护任何充当安全边界的公共属性

TIP

模型属性默认是安全的

若将 Eloquent 模型存储在公共属性中,Livewire 会自动确保 ID 不被篡改——无需 #[Locked] 属性:

php
<?php // resources/views/components/post/⚡show.blade.php

use Livewire\Component;
use App\Models\Post;

new class extends Component {
    public Post $post; // Already protected [tl! highlight]

    public function mount($id)
    {
        $this->post = Post::find($id);
    }
};

为什么不用 protected 属性?

你可能会疑惑:为什么不能直接用 protected 属性存放敏感数据。

请记住,Livewire 仅在请求之间持久化公共属性。protected 属性适用于静态、硬编码的值,但任何需要在运行时保存的数据都必须使用公共属性,才能在请求之间正确持久化。

这正是 #[Locked] 的关键所在:它既提供公共属性的持久化能力,又防止客户端篡改。

Livewire 不能自动做到吗?

在理想情况下,Livewire 会默认锁定属性,仅在该属性使用了 wire:model 时才允许修改。

遗憾的是,这需要 Livewire 解析你所有的 Blade 模板,以判断属性是否被 wire:model 或类似 API 修改。

这不仅会增加技术与性能开销,而且若属性被 Alpine 或其他自定义 JavaScript 修改,也无法检测。

因此,Livewire 将继续默认让公共属性可自由修改,并提供工具让开发者按需锁定它们。