Laravel Breezeでユーザーの権限による認可


Laravel BreezeでUserモデル一つ、roleで権限を分けてみました。
実運用はまだしていません。お試し中です。

Laravel Breezeのインストールはこちらを参照してください。
Laravel Breezeインストール済みであることで進めます。

権限は以下の3つにしてます。
admin company user
まずはusersテーブルにroleカラムを追加します。

migrations
class AddRoleToUserTable extends Migration
{

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('role');
        });
    }

    public function down()
    {
        Schema::table('user', function (Blueprint $table) {
            $table->dropColumn('role');
        });
    }
}

ログイン後やユーザー登録後のリダイレクト先を割り振ります。

app/Providers/RouteServiceProvider.php
    public const HOME = '/';
    public const COMPANY = '/post/list';
});

userにcompanyを登録するためのメソッドcreatecompanyとstorecompanyをRegisteredUserControllerコントローラーにcreate、storeメソッドをコピーして追加。roleを割り振ります。
storeメソッドにもroleを指定してください。
会社登録用のregister画面を分けたいのでregister.phpをコピーしてregister-companyというビューも作ってます。
storecompanyで登録処理が終わったらCOMPANYに飛びます。

HTTP/Controller/Auth/RegisteredUserController.php

//追加画面
    public function createcompany()
    {
        return view('auth.register-company');   
    }
//登録処理
    public function storecompany(Request $request)
    {
        $request->validate([
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|confirmed|min:8',
        ]);

        Auth::login($user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'role' => 'company',
            'password' => Hash::make($request->password),
        ]));

        event(new Registered($user));

        return redirect(RouteServiceProvider::COMPANY);
    }
});

管理者、会社、一般ユーザーの権限を分けるため、AuthServiceProviderにgateを書きます。

app/Providers/AuthServiceProvider.php
    public function boot()
    {
        $this->registerPolicies();

        //管理者か
        Gate::define('isAdmin',function($user){
           return $user->role == 'admin';
        });

        //会社か
        Gate::define('isCompany',function($user){
           return ($user->role == 'company' || $user->role == 'admin');
        });

        //POSTをアップデートできるのはuser->idが同じ
        Gate::define('update-post', function ($user, $post) {
            return $user->id === $post->user_id;
        });

        //POSTを消せるのはuser->idが同じ
        Gate::define('delete-job', function ($user, $post) {
            return $user->id === $post->user_id;
        });
    }
});

管理者以外companyをレジストできなくしたいので
Routeでgateを通れるisAdmin以外通れなくします。

routes/auth.php
// 管理者
Route::group(['middleware' => ['auth', 'can:isAdmin']], function () {
    Route::get('/registercompany', [RegisteredUserController::class, 'createcompany'])
                    //ログイン済みであればトップページにリダイレクトされる処理をコメントアウト
                    //->middleware('guest')
                    ->name('registercompany');

    Route::post('/registercompany', [RegisteredUserController::class, 'storecompany']);
                    //ログイン済みであればトップページにリダイレクトされる処理をコメントアウト
                    //->middleware('guest');
});

ログイン画面は同じメソッドで処理したいです。
ただしログイン後の画面は管理者とユーザーで分けたいので
AuthenticatedSessionControllerでユーザー権限引っ張って分岐します。

HTTP/Controller/Auth/AuthenticatedSessionController.php
    public function store(LoginRequest $request)
    {
        $request->authenticate();
        $request->session()->regenerate();
        //ユーザーによりログイン先を変更
        $user = Auth::user();
        if($user->role == 'admin'){
            return redirect(RouteServiceProvider::COMPANY);
        } elseif ($user->role == 'company') {
            return redirect(RouteServiceProvider::COMPANY);
        } elseif ($user->role == 'user') {
            return redirect(RouteServiceProvider::HOME);
        } else {
            return redirect('/')->with('flash_message', 'ユーザ一覧にアクセスが許可されていないユーザです。');
        }
    }

あとは各メソッドでgateを呼びます。これは編集

HTTP/Controller/PostEdit.php
class PostEdit extends Controller
{
    public function __invoke($id)
    {
        $user = Auth::user();
        $post = post::findOrFail($id);

        if (Gate::forUser($user)->allows('update-post', $post)) {
            // 渡されたユーザーはこのpost.editを表示できる。
            return view('post.edit', compact('post'));

        } elseif (Gate::allows('isAdmin')) {
            //adminは許可
            return view('post.edit', compact('post'));
        } else {
            return redirect('/')->with('flash_message', '編集できませんでした!');
        }      
    }
}

改修が必要ですがひとまず。