Laravel Permissionを使用して簡単に権限を付与する

# この記事の目的
一人のユーザーにいくつかの権限を付与したい。でも多対多のリレーションってややこしくないですか？
このライブラリを使えば中間テーブルを自分で作るよりずっと楽！！と分かったので誰にでもわかる備忘録を目指して書いていきます。

# Laravel Permissionとは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367698/f6f86e5a-2be6-5869-e307-9415fb749adf.png)

LaravelのSpatie/Permissionパッケージは、ユーザー（User）と役割（Role）を紐づけるため（もちろん違うテーブルでも可能です）の中間テーブルを管理するライブラリです。このパッケージを使用することで、Laravelアプリケーションの権限管理機能を簡単に実装することができます。

　**-Laravel Permissionでできること-**
　**・ユーザーに役割を割り当てる（UserとRoleの紐づけ）**
　**・ユーザーが特定の役割を持っているかどうかのチェック**
　**・役割に基づいたアクセス制御の実装**
　**・権限の管理（権限の作成、削除、編集など）**


# 環境
・Laravel 10.x
・spatie/laravel-permission
・MySQL

※今回はユーザー認証にLaravel Breezeを利用しています。前提としてLaravelプロジェクトの立ち上げ、Breezeのインストール、データベース接続が完了としていることとします。


# インストール～設定
ライブラリをインストールします。
```
composer require spatie/laravel-permission
```

サービスプロバイダの登録をします。ドキュメントでは自動的に登録されると書いてあったのですが、入ってなかったので手動で記述しました。
```php:/config/app.php 
'providers' => [
    // ...省略
    Spatie\Permission\PermissionServiceProvider::class,
];
```

プロバイダを登録したら以下のコマンドを実行します。
```
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider
```
\config\permission.phpと\migrations\xxxx_xx_xx_xxxxxx_create_permission_tables.phpが作成されました。

ここで設定を反映させるためキャッシュをクリアしておきましょう。
```
php artisan config:clear
```
permissionテーブルを作成するためにマイグレーションを実行します。

```
php artisan migrate
```
その前にrolesテーブルは？と思った方！私も思いました(笑)
どうやら作らなくていいみたいです。マイグレーション後作成されたテーブルを見てみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367698/5c9e0d41-4601-a96a-c96d-cee8476ddb4c.png)
細かいことは省きますが、rolesテーブルは自動生成されます。

roleを紐づけるUserモデルに以下を記載します。
```php:App/Models/User.php
use Spatie\Permission\Traits\HasRoles; // 追加

class User extends Authenticatable
{

    use HasRoles; // 追加

    // ...省略
}
```

これでLaravel Permissionを使用する準備は整いました。

# 役割と権限の作成
ここで間違えてはいけないのが、**Role(役割)**　と　**Permission(権限)**　です。
Permission(権限)は直接ユーザーではなくRole(役割)に与えるのが推奨されます。

例を挙げます。
管理者と利用者いうRole(役割)があります。
管理者は『利用者を登録する』というPermission(権限)があります。
利用者にはその権限がありません。
登録の担当がAさんからBさんに変わったとします。
その時にBさんに直接権限を付与することもできます。が、Aさんから権限を剥奪するという手間がかかります。また、間違ってCさんに権限を与えてしまう可能性もあります。
なので管理者という役割に権限を与えて、管理者をAさんからBさんに変更する方が間違いが少ないです。

ということで、Role(役割)にPermission(権限)を与えていきます。
今回はマスタデータ用のSeederを作成します。

```
php artisan make:seeder MasterDatabaseSeeder
```

作成したseederファイルを記述していきます。
```php:database/seeders/MasterDatabaseSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role; // 追加
use Spatie\Permission\Models\Permission; // 追加
use App\Models\User; // 追加

class MasterDatabaseSeeder extends Seeder
{

    public function run()
    {
        // ユーザー作成
        $president = User::create([
            'name' => '社長',
            'email' => 'president@sample.com',
            'password' => bcrypt('password'),
            ]);

        User::create([
            'name' => '社員1',
            'email' => 'gest@sample.com',
            'password' => bcrypt('password'),
            ]);


        // ロール作成
        $adminRole = Role::create(['name' => 'admin']);

        // 権限作成
        $registerPermission = Permission::create(['name' => 'register']);


        // admin役割にregister権限を付与
        $adminRole->givePermissionTo($registerPermission);

        // 社長にadminを割り当て
        $president->assignRole($adminRole);
    }
}

```

ここでは、

　・社長と社員というユーザー
　・**admin(管理者)** というRole(役割)
　・**register(利用者登録)** というPermission(権限)

を作成し、

　・**admin(管理者)** に **register(利用者登録)** を付与
　・社長に **admin(管理者)** を割り当て

しています。

では権限が付与できたか確認してみましょう！

ダッシュボードの{{ __("You're logged in!") }}を書き換えてみます。

```php:resource/views/dashboard.blade.php
<x-app-layout>
    <x-slot name="header">
        <h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
            {{ __('Dashboard') }}
        </h2>
    </x-slot>

    <div class="py-12">
        <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
            <div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm sm:rounded-lg">
                <div class="p-6 text-gray-900 dark:text-gray-100

                    {{-- 変更ここから --}}

                    @can('register')
                    <p>register権限を持つ人だけが見れるよ</p>
                    @endcan
                    <p>みんな見れるよ</p>

                    {{-- ここまで --}}

                </div>
            </div>
        </div>
    </div>
</x-app-layout>

```
@can('register')で囲っている部分はregister(利用者登録)権限を持っている人のみが見ることができる部分になります。

社長アカウントでログインします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367698/df3985b8-dc69-c9be-2d45-d146379a1659.png)

社員アカウントでログインします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3367698/f48d488b-30dc-404e-2d77-616a553a72f8.png)


このように表示が変わりました！
ちなみに、権限でなく役割で表示を変えることもできます。
```php
  @hasanyrole('admin')
  <p>役割がadminの人だけが見れるよ</p>
  @endhasanyrole
```
@canではなく、@hasanyrole('Role名')にするだけです。


以上Laravel Permissionで権限を付与する方法でした。