昨今の人間が閲覧する web ページは大体 HTML 形式のデータをやり取りしており、 HTML 中の記述を元に JavaScript、CSS、画像、フォントなどなどのアセットファイルを HTML に加えて更に読み込みます。また、ログイン機能があるサイトではページそのものである HTML やサーバに置いてあるデータを取得するための API に認証が必須になっていることがよくあります。この認証必須の領域で取り扱うアセットファイルにも認証機能を付けたい時があります。Laravel で簡単にアセットファイルに認証機能をつける方法を紹介します。
コード例が次です。
/** /routes/web.php */
/*
* このルーティングは例えば次の動きをします。
*
* http://laravel.example.com/auth_storage/admin/js/app.js にアクセスされた時
* if(管理者として認証済み === true){
* return /storage/auth_storage/admin/js/app.js の内容レスポンス
* } else {
* return 認証エラーレスポンス
* }
*/
Route::prefix('auth_storage')->group(static function () {
Route::middleware('auth:admin')
// 認証していなければアクセスできなくする Laravel 組み込みの認証ミドルウェアを使う、と定義します
->get('/admin/{any}', static fn ($any) => \Storage::disk('auth_storage_admin')->exists($any)
? \Storage::disk('auth_storage_admin')->response($any)
: abort(404)
)
// このルーティングに引っかかった場合、anyの値に合わせてファイルが存在するかチェックして、
// 存在するならばファイル送信レスポンスを返し、存在しないならば 404 で処理を終わらせます。
->where('any', '.*');
// {any} には.*の正規表現(任意文字の無限長)を含む文字列が当てはまります
// @see https://readouble.com/laravel/6.x/ja/routing.html?header=スラッシュのエンコード
});
/** /config/filesystems.php */
// Laravel のファイルストレージ設定ファイル
// 省略
'disks' => [
// 他ディスク定義を省略
'auth_storage_admin' => [
'driver' => 'local',// ローカルのファイルシステムを使うと定義
'root' => storage_path('auth_storage/admin'), // /storage/auth_storage/admin がストレージディスクのルートであると定義
'url' => env('APP_URL').'/auth_storage/admin', // \Storage::disk('auth_storage_admin')->url() で返される URL の前置詞を定義
],
]
// 省略
これだけで storage/auth_storage/admin 以下のファイルを認証必須にできます。コントローラクラスを作りたくなる程長いコードは必要もありません。Laravel 7.x 以前のバージョンで route:cache コマンドを使ったルーティングキャッシュを作りたい場合はコントローラを作る必要がありますが、8.x ならばそれもありません。
ここまでやると JavaScript、CSS のコンパイル結果ファイルを /public 以下ではなく /storage/hoge 以下に置きたくなります。これは次でできます。
/** webpack.mix.js */
// eslint-disable-next-line no-undef,@typescript-eslint/no-var-requires
const mix = require('laravel-mix');
mix
.setPublicPath('')// laravel-mix の出力先のルートディレクトリ(デフォルトでは public 想定)はプロジェクトルートである、と定義
.js('resources/js/admin/app.ksx', 'storage/auth_storage/admin/js')// /storage 以下に出力
.sass('resources/sass/admin/app.scss', 'storage/auth_storage/admin/css')// /storage 以下に出力
.sass('resources/sass/public/app.scss', 'public/css')// /public 以下に出力
;
これを行うと mix-manifest.json がプロジェクトルートに現れ、helper 関数の mix がそのままでは使用できなくなりますが、次の様に hash_file 関数を代用することでキャッシュが効いてファイルの更新が反映されない、といったことを防げます。
PHP: hash_file – Manual
<script src="{{ \Storage::disk('auth_storage_admin')->url('js/app.js') }}?{{ hash_file('sha1', \Storage::disk('auth_storage_admin')->path(js/app.js)) }}"></script>
この様に案外凝ったことをせずともファイルに認証処理をつけられます。