🙆‍♀️

Laravel11でGate使ってUserをroleでルート分岐させるゾ

2024/04/03に公開

UserとAdmin分けたいんだけど、大規模なサイトじゃないからAdmin1人だし、それならマルチ認証でつくるほどでもないよね?ってときあるよね。
そういう時はUserモデルにroleっていう権限カラム持たせて、その値で判断しよう。
そして、その値で、Adminだけの管理ページに飛ばせば、普通のuserはページに入れない。
こんな感じの構成を作ってみたいと思います。
User認証用に、Breezeがインストールされている前提です。

マイグレーションでUserモデルにカラム追加

UserとAdminを区別するために、Userテーブルにroleカラムを作成します。
値は、普通にStringで(user or admin)でいきます。
ターミナルに次のコードを入力します。

php artisan make:migration add_users_table_1column --table=users

これで追加用のテーブルが作成されました。
中身に次のコードを入力します。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('role')->default('general')->comment('権限名')->after('password');
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('role');
        });
    }
};

これは、usersテーブルのpasswordカラムの下に、roleカラムを作ってという内容になります。
カラムのデフォルト値はgeneralで、adminにしたいuserだけadminとPHPMyAdminなどで手動更新します。
また、SeederでAdmin用データを入れても良いです。
ファイルができたら、次のコードでマイグレーションします。

php artisan migrate

これでデータベースのusersテーブルにroleカラムができました。
usersの中でAdminにしたい人のroleをadminに変えておいてください。

ProvidersにAuthServiceProviderを作ろう

laravelの11になってからProvidersにファイルはありません。
ターミナルから自分で作る必要があります。

php artisan make:provider AuthServiceProvider.php

これでapp/providersの中にAuthServiceProviderが作成されます。
以下のコードをコピーして貼り付けます。

<?php

namespace App\Providers;

use App\Models\User;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The model to policy mappings for the application.
     *
     * @var array<class-string, class-string>
     */
    protected $policies = [
        //
    ];

    public function boot()
    {
        $this->registerPolicies();

        Gate::define('admin', function (User $user) {
            if ($user->role === 'admin') {
                return true;
            } else {
                return false;
            }
        });

    }
}

これは、認証時にGateにadminを設定しています。
Userモデルのroleがadminならば、Gateにadminを設定して返す。それ以外は返さない。
といった感じの内容になってます。

Laravel10まではここに書くだけで良かったのですが、Laravel11になってからは、このAuthServiceProvider.php自体をアプリスタート時に読み込ませなければいけません。
bootstrap/providers.phpにこのファイルを追加する必要があります。

<?php

return [
    App\Providers\AppServiceProvider::class,
    App\Providers\AuthServiceProvider::class,
];

ログイン時にAdmin用のダッシュボードにとばしたい

app/Http/Controllers/Authに認証用のファイルが入っています。
この中で、AuthenticatedSessionController.phpがログイン用のファイルとなっています。
storeメソッドがログインリクエストになりますので、ここで、認証が済みセッションが再生成されたあと、ダッシュボードに飛ぶように書いてありますが、これをGateでadminに設定されていたらadminダッシュボードに飛ばすように追加で修正します。

<?php
use Illuminate\Support\Facades\Auth;//追加
use Illuminate\Support\Facades\Gate;//追加

    public function store(LoginRequest $request): RedirectResponse
    {
        $request->authenticate();

        $request->session()->regenerate();

        if (Gate::allows('admin', Auth::user())) {
            return redirect()->intended(route('admin.dashboard', absolute: false));
        }

        return redirect()->intended(route('dashboard', absolute: false));
    }

これで処理は完了です。

dashboardファイルを作る

Adminのときに開く専用のダッシュボードファイルを作ります。
resources/views にdashboard.blade.phpがあるので、これをコピーして、admin-dashboard.blade.phpにリネームします。
中に<x-app-layout>と記載があると思うのでこれをx-admin-layoutに修正します。
h1のWelcome to your dashboardと書かれた文字のあたりにわかりやすくADMINと書いておきます。

次に、layoutsフォルダの中のapp.blade.php/navigation.blade.phpをそれぞれコピーして、admin.blade.php/admin-navigation.blade.phpに修正します。
admin.blade.phpの中にある@include('layouts.navigation')を@include('layouts.admin-navigation')に修正します。
admin-navigation.blade.phpの中のroute('dashboard')はroute('admin.dashboard')に変更します。
最後に、app/ViewフォルダのAppLayout.phpをコピーして、Adminlayout.phpに直し以下のコードをコピーします。

<?php

namespace App\View\Components;

use Illuminate\View\Component;
use Illuminate\View\View;

class AdminLayout extends Component
{
    /**
     * Get the view / contents that represents the component.
     */
    public function render(): View
    {
        return view('layouts.admin');
    }
}

ルートファイルに分岐を記載する

処理は完成したのでroutes/auth.phpでRouteを記入していきます。
ログインは共通なので、そのあとのログイン後にいくURLを記入していきます。

<?php
Route::get('/admin/dashboard', function () {
            return view('admin-dashboard');
})->middleware(['auth', 'can:admin', 'verified'])->name('admin.dashboard');

最後に構成をクリアします。

php artisan optimize

以上で、終了です。
これで、通常のログイン画面からadminでログインして、Admin専用ダッシュボードが表示されていれば成功です。

ここから先は、prefixやnameでadminを分けて、routeファイル自体も分けて処理をしていくと便利だと思います。

お疲れ様でした🤗

Discussion