[Laravel 8.x]「419 | PAGE EXPIRED」が発生する

Laravel

はじめに

view@csrfが入っていないから発生するって記事が多すぎ…
入れていてもセッション切れで発生するし、こんなページが表示されてもユーザー(利用者)はどうすればよいかわからない。

419エラー画面にログイン画面へ遷移するリンクを付けるとか、
強制的気にログイン画面へ遷移するかぐらいが利用者はわかりやすいかと思う。

そもそもcsrfってなんやねん

ここ(https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%82%B9%E3%82%B5%E3%82%A4%E3%83%88%E3%83%AA%E3%82%AF%E3%82%A8%E3%82%B9%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%82%B8%E3%82%A7%E3%83%AA)参照。

原因

  1. そもそも@csrfviewにない。
  2. セッションが切れて(or csrfを改ざんして)POSTした。

この2パターンかなと。厳密に言ったらもっとあるんやろうけど。

@csrfがviewにない場合

view@csrfを入れましょう。

<form method="POST" action="{{ route('login') }}">
    @csrf  // この行を入れましょう!
      :
      :
</form>

セッション切れ or csrf改ざん

419エラー画面をカスタマイズ

まずは、Laravel側のエラー画面をコピーする。

% php artisan vendor:publish --tag=laravel-errors
Copied Directory [/vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/views] To [/resources/views/errors]
Publishing complete.

こんな感じでファイルが出来上がる。

/resources/views/errors
├── 401.blade.php
├── 403.blade.php
├── 404.blade.php
├── 419.blade.php
├── 429.blade.php
├── 500.blade.php
├── 503.blade.php
├── illustrated-layout.blade.php
├── layout.blade.php
└── minimal.blade.php

401〜503は、minimal.blade.phpを参照しているので、こいつにログイン画面への遷移を追加してあげればよいかと思う。

<body class="antialiased">
    <div class="relative flex items-top justify-center min-h-screen bg-gray-100 dark:bg-gray-900 sm:items-center sm:pt-0">
        <div class="max-w-xl mx-auto sm:px-6 lg:px-8">
            <div class="flex items-center pt-8 sm:justify-start sm:pt-0">
                <div class="px-4 text-lg text-gray-500 border-r border-gray-400 tracking-wider">
                    @yield('code')
                </div>

                <div class="ml-4 text-lg text-gray-500 uppercase tracking-wider">
                    @yield('message')
                </div>
            </div>

            <!-- このブロックを追加 -->
            <div class="flex items-center pt-8 sm:justify-start sm:pt-0">
                <div class="px-4 text-lg text-gray-500 border-gray-400 tracking-wider">
                    <a href="{{ route('login') }}">ログイン</a>
                </div>
            </div>

        </div>
    </div>
</body>

ログインへリダイレクト

こんなエラー画面を利用者に見せる必要はないと思ってる。だからログインへリダイレクトすればいいんじゃない?

app/Exceptions/Handler.php

use Illuminate\Session\TokenMismatchException; // 追加

class Handler extends ExceptionHandler
{
     :
     :
     :

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Throwable  $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Throwable $exception)
    {
        // Tokenエラーの時、ログイン画面にリダイレクトする。
        if ($exception instanceof TokenMismatchException) {
            return redirect(route('login'));
        }

        return parent::render($request, $exception);
    }
     :
     :
     :

まとめ

やりやすいようにやればいいと思う。

コメント

タイトルとURLをコピーしました