新しいLivewire開発者には、Livewireでの体験はちょっとした魔法のようなものです。ページが読み込まれると、Livewire コンポーネントがサーバ上に存在し、ブラウザからの更新を待ち、リアルタイムに応答しているかのように感じられます。
これは、のような他の類似したツールの動作と変わりありません。
Livewireは、似ているようでいて、内部構造は全く異なり、それぞれに長所、短所、セキュリティ上の影響があります。
Livewireコンポーネントは「ステートフル」に感じられますが、完全に「ステートレス」です。サーバ上にブラウザのインタラクションを待ち、長時間稼働するLivewireインスタンスはありません。それぞれのインタラクションは、全く新しいできたてのリクエスト/レスポンスです。
このメンタルモデルをもっと理解するため、次のようなシンプルな「カウンター」コンポーネントを手始めに考えてみましょう。
class Counter extends Component
{
public $count = 1;
public function increment()
{
$this->count++;
}
public function render()
{
return view('livewire.counter');
}
}
app/Http/Livewire/Counter.php
<div>
<h1>{{ $count }}</h1>
<button wire:click="increment">+</button>
</div>
resources/views/livewire/counter.blade.php
この「カウンター」をユーザーの視点で使ってみると、ユーザーがページを読み込み、「1」という数字を見て、「+」ボタンをクリックし、次に「2」という数字を見ることになります。
以下に、Livewireが実際にどのような動作をするかを図示します。
要約すると、ユーザーが"counter"コンポーネントを含むページにアクセスすると"counter"の初期表示がレンダーされますが、HTMLのレンダリングに加えて、Livewireはコンポーネントの状態(パブリックプロパティ)を「デハイドレイド」または「シリアライズ」して、フロントエンドに渡します。
これで現状、フロントエンドがコンポーネントの状態を把握しているので、更新がトリガーされると(このケースでは"+"をクリックすると)、最後に把握したコンポーネントの状態を含んだリクエストがサーバーに送信されます。サーバーは、その状態からコンポーネントを「ハイドレート」または「デシリアライズ」し、更新を行います。
コンポーネントは再びデハイドレイドされ、新たにレンダリングされたHTMLと更新済みの状態をブラウザへ提供し、後のインタラクションリクエストで使用できるようになります。
次に、こうしたリクエスト時における、実際のコンポーネントのライフサイクルをより深く図示します。
Livewire が内部でどのように動作するか、より正確なメンタルモデルを理解していただければ、幸いです。これにより、より懸命に問題をデバッグしたり、Livewire を使用することによるパフォーマンスやセキュリティへの影響を理解できます。
セキュリティ対策
前述の通り、Livewireの各リクエストは「ステートレス」であり、状態を維持するため長時間稼働するサーバインスタンスは存在しません。状態はブラウザに保存され、リクエストの間にサーバーとの間でやり取りされます。
状態がブラウザに保存されるため、フロントエンドによる操作には脆弱です。セキュリティ対策が施されていなければ、悪意のある人により、リクエスト間でブラウザ内のコンポーネントの状態を簡単に操作されてしまいます。
先ほどの「カウンター」の例では、そのコンポーネントの「カウント」のような些細で一時的なものを操作しても、実際には悪影響はありませんが、例えば削除ボタン付きの「投稿編集」コンポーネントのように、より多くの問題を抱えるコンポーネントでは、セキュリティ対策を講じる必要があります。
チェックサム
Livewireを支える基本的なセキュリティは、リクエスト/レスポンスと一緒に移動する「チェックサム」であり、サーバーからの状態がブラウザ内で改ざんされていないことを検証するために使用されます。
さらに説明すると、上記の「カウンター」コンポーネントを考えてみましょう。単に
[{ count: 1 }
]{style="white-space: nowrap"}
をブラウザに渡すのではなく、Livewire
は安全な鍵を使ってそのペイロードのハッシュ(チェックサム)を生成し、それを状態と一緒に渡します。
「カウンター」のためのLivewireペイロードをより現実的に表現すると、次のようになります。
{
state: { count: 1 },
checksum: "A6jHn359Ku3lFc82arW8",
}
ここで、悪意のある人がリクエストの間にブラウザの状態を改ざんした場合、Livewireがコンポーネントの更新を処理する前に、ペイロードのハッシュがチェックサムと一致しないことがわかり、エラーが発生します。
持続ミドルウェア
Livewire が施す、セキュリティ対策の2つ目は「永続的ミドルウェア」です。つまり、Livewireは「最初のリクエスト」の際に使用された認証/認可ミドルウェアを捕捉し、その後のリクエストに再適用します。
この対策がなければ、ユーザーがアプリケーションからログアウトした後に、Livewire の後続リクエストがキャプチャされ、再実行される可能性があり、そうしたコードパスへのアクセスはできなくなります。
デフォルトでは、Laravelアプリに用意されている認証と認可のミドルウェアを適用します。ここでは、デフォルト設定を一部紹介します。
[
...
\Illuminate\Auth\Middleware\Authenticate::class,
\Illuminate\Auth\Middleware\Authorize::class,
]
独自のミドルウェアを追加してキャプチャし、存在する場合に再適用したい場合は、以下のAPIを使ってアプリのサービスプロバイダで行うことができます。
Livewire::addPersistentMiddleware([
YourOwnMiddleware::class,
]);
追加したミドルウェアは、コンポーネントがロードされた元のルートにミドルウェアが割り当てられていれば、その後のLivewireリクエストでも再適用されます。