Laravelでユーザーごとの権限を管理するlaravel-permissionをインストールする

Laravelでユーザーごとの権限を管理するlaravel-permissionをインストールして使用する導入部分を紹介します。
使用しているのは Laravel5.6 と Mysql, nginx です。

● Laravel Permission

1. Laravelのテストアプリの作成

permission_appというテストアプリを作成します。

laravel new permission_app

2. DB作成と .env へDB情報を保存

DB作成は phpmyadmin などで作成してください。
その後 .env に接続情報を書き込みます

.env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<YOUR-DB-NAME>
DB_USERNAME=<YOUR-USER-NAME>
DB_PASSWORD=<YOUR-PASSWORD>

3. authのインストールとDBマイグレーション

php artisan make:auth
php artisan migrate

4. nginxの設定 (不要な方は飛ばしてください)

新たにバーチャルホストを作成します。
設定ファイル「permissionapp.conf」を新規作成します。

vi /etc/nginx/conf.d/permissionapp.conf 

permissionapp.conf を下記の内容で保存

server {
    listen  80;
    server_name permissionapp.local;
    location / {
       root  /var/www/html/la/permission_app/public;
       index index.php index.html index.htm;
       try_files $uri $uri/ /index.php$is_args$args;

     }
     location ~ \.php$ {
       fastcgi_pass 127.0.0.1:9000;
       fastcgi_index index.php;
       fastcgi_param SCRIPT_FILENAME /var/www/html/la/permission_app/public/$fastcgi_script_name;
       include fastcgi_params;
     }
 }

5. hosts へサーバ名をセット(不要な方は飛ばしてください)

hosts に下記の内容を追記します。
IPアドレス「192.168.1.99」は適宜書き換えてください。

192.168.1.99 permissionapp.local

6. アプリへアクセス

http://permissionapp.local/
へアクセスして一通りユーザー登録などの動作を確認します。

● Laravel-Permission のインストール

1. laravel/passport , laravel-permission を composerからインストールする

composer require spatie/laravel-permission

2. config/app.phpに追記

config/app.php (163行目あたり)

'providers' => [
    // ...
    Spatie\Permission\PermissionServiceProvider::class,
];

3. app/Http/Kernel.php に追記

app/Http/Kernel.php(61行目あたり)

protected $routeMiddleware = [
    ....
    'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
    'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
]
....

3. DBテーブルのマイグレーション

artisanコマンドで マイグレーションファイルを生成します

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="migrations"

次のようなファイルが生成されます

./database/migrations/2020_03_06_211512_create_permission_tables.php

2020_03_06_211512_create_permission_tables.php の中にDBテーブルを作成するコードが記述されます。
作成されるテーブルは次の5つ

permissions
roles
model_has_permissions
model_has_roles
role_has_permissions

4. コンフィグファイルのマイグレーション

php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider" --tag="config"

次の1ファイルが作成されます

./config/permission.php

5. DBテーブルの作成

php artisan migrate

DBテーブルが作成されます。

● 権限の設定

例として次のような権限で設定を行いたいと思います。
(権限はメソッドごとに設定してもいいですし、クラスごとに設定してもいいと思います。ここでは簡単に3段階の権限としています)

役割「グループ」(Role) 持つ権限(Permission)
admin admin_permission , manager_permission , staff_permission
manager manager_permission , staff_permission
staff staff_permission

● DBデータの作成

1. PermissionTableSeeder.php

php artisan make:seeder PermissionTableSeeder

app/database/seeds/PermissionTableSeeder.php

<?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
class PermissionTableSeeder extends Seeder
{
    public function run()
    {
        $permissions = [
            'admin_permission',
            'manager_permission',
            'staff_permission',
        ];
        foreach ($permissions as $permission) {
            Permission::create(['name' => $permission]);
        }
    }
}

2. RoleTableSeeder.php

php artisan make:seeder RoleTableSeeder

app/database/seeds/RoleTableSeeder.php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
class RoleTableSeeder extends Seeder
{
    public function run()
    {
        $roles = [
            'admin',
            'manager',
            'staff',
        ];
        foreach ($roles as $role) {
            Role::create(['name' => $role]);
        }
    }
}

3. RoleHasPermissionTableSeeder.php

php artisan make:seeder RoleHasPermissionTableSeeder

app/database/seeds/RoleHasPermissionTableSeeder.php

<?php

use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
class RoleHasPermissionTableSeeder extends Seeder
{
    public function run()
    {
        // admin
        $permissions = [
            'admin_permission',
            'manager_permission',
            'staff_permission',
        ];
        $role = Role::findByName('admin');
        $role->givePermissionTo($permissions);

        // manager
        $permissions = [
            'manager_permission',
            'staff_permission',
        ];
        $role = Role::findByName('manager');
        $role->givePermissionTo($permissions);

        // staff
        $permissions = [
            'staff_permission',
        ];
        $role = Role::findByName('staff');
        $role->givePermissionTo($permissions);
    }
}

4. UserTableSeeder.php

php artisan make:seeder UserTableSeeder

app/database/seeds/UserTableSeeder.php

use App\User;
use Illuminate\Database\Seeder;
class UserTableSeeder extends Seeder
{
    public function run()
    {
        // admin
        $user = User::create([
            'name'     => '管理 太郎',
            'email'    => 'admin@localhost',
            'password' => Hash::make('admin'),
        ]);
        $user->assignRole('admin');

        // manager
        $user = User::create([
            'name'     => 'マネージャー大森',
            'email'    => 'manager@localhost',
            'password' => Hash::make('manager'),
        ]);
        $user->assignRole('manager');

        // staff
        $user = User::create([
            'name'     => 'スタッフ 花子',
            'email'    => 'staff@localhost',
            'password' => Hash::make('staff'),
        ]);
        $user->assignRole('staff');
    }
}

5. シーダーの実行

 php artisan db:seed --class=PermissionTableSeeder
 php artisan db:seed --class=RoleTableSeeder
 php artisan db:seed --class=RoleHasPermissionTableSeeder
 php artisan db:seed --class=UserTableSeeder

OFF php artisan db:seed –class=ModelHasRoleTableSeeder OFF

もし class not foundエラーが出る場合は

composer dump-autoload

を実行してから再度実行すること。

● メソッド一覧

Permission

public static    create(array $attributes = [])
public           roles(): BelongsToMany
public           users(): MorphToMany
public static    findByName(string $name, $guardName = null): PermissionContract
public static    findById(int $id, $guardName = null): PermissionContract
public static    findOrCreate(string $name, $guardName = null): PermissionContract
protected static getPermissions(): Collection

Role

public static    create(array $attributes = [])
public           permissions(): BelongsToMany
public           users(): MorphToMany
public static    findByName(string $name, $guardName = null): RoleContract
public static    findById(int $id, $guardName = null): RoleContract
public static    findOrCreate(string $name, $guardName = null): RoleContract
public           hasPermissionTo($permission): bool

Userモデルなど既存のモデルに追加される拡張メソッド

use HasRoles; で拡張されるメソッド

use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
    use HasRoles;
    ..........

public static        bootHasRoles()
public       roles(): MorphToMany
public       scopeRole(Builder $query, $roles): Builder
public       assignRole(...$roles)
public       removeRole($role)
public       syncRoles(...$roles)
public       hasRole($roles): bool
public       hasAnyRole($roles): bool
public       hasAllRoles($roles): bool
public       getDirectPermissions(): Collection
public       getRoleNames(): Collection
protected        getStoredRole($role): Role
protected        convertPipeToArray(string $pipeString)

use HasPermissions; で拡張されるメソッド

use Spatie\Permission\Traits\HasPermissions;
class User extends Authenticatable
{
    use HasPermissions;
    ..........

public static        bootHasPermissions()
static::deleting(        ($model) {
public       permissions(): MorphToMany
public       scopePermission(Builder $query, $permissions): Builder
protected        convertToPermissionModels($permissions): array
public       hasPermissionTo($permission, $guardName = null): bool
public       hasAnyPermission(...$permissions): bool
public       hasAllPermissions(...$permissions): bool
protected        hasPermissionViaRole(Permission $permission): bool
public       hasDirectPermission($permission): bool
public       getPermissionsViaRoles(): Collection
public       getAllPermissions(): Collection
public       givePermissionTo(...$permissions)
public       syncPermissions(...$permissions)
public       revokePermissionTo($permission)
protected        getStoredPermission($permissions)
protected        ensureModelSharesGuard($roleOrPermission)
protected        getGuardNames(): Collection
protected        getDefaultGuardName(): string
public       forgetCachedPermissions()

● Bladeビューでの権限(Permission)判定

次のようにして blade テンプレート内で権限(Permission)を判別することができます。通常こちらを使用すると思います。

<p>
    @can('admin_permission')
        admin_permission を持っています <br>
    @endcan

    @can('manager_permission')
        manager_permission を持っています <br>
    @endcan

    @can('staff_permission')
     staff_permission を持っています <br>
    @endcan
</p>

● Bladeビューでのロール(Role)判定

ロール(Role)を判別したいときはこちらを使用します

<p>
    @role('admin')
        あなたのロールは admin です<br>
    @endrole                    

    @role('manager')
        あなたのロールは manager です<br>
    @endrole                    

    @role('staff')
        あなたのロールは staff です<br>
    @endrole                    
</p>

● Routes での権限、ロール判定

app/Http/Kernel.php (63行目あたり)

protected $routeMiddleware = [
    // ...
    'role' => \Spatie\Permission\Middlewares\RoleMiddleware::class,
    'permission' => \Spatie\Permission\Middlewares\PermissionMiddleware::class,
];

Routesには以下のように記述します
App/routes/web.php

// 誰でもアクセス可能
Route::resource('users', 'UserController');

 ↓

// 「ログイン」している時のみアクセス可能
Route::group(['middleware' => ['auth']], function() {
    Route::resource('users', 'UserController');
});

 ↓

// 「ログイン」かつ「admin_permissionを持つ」時のみアクセス可能
Route::group(['middleware' => ['auth']], function() {
    Route::group(['middleware' => ['permission:admin_permission']], function () {
        Route::resource('users', 'UserController');
    });
});

です。

● 権限(permissions)やロール(roles)の一覧を取得する

モデルを作成します。

/app/Permission.php

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Permission extends Model
{
    protected $table = 'permissions';
    protected $guarded = ['id', 'created_at', 'updated_at'];
}
// 全ての permissionsの取得
\App\Permission::get();

● There is no permission named xxxxx_permission for guard web. というエラーが出る場合の対処法

こちらのエラーですが、DBの permissions を変更した後、キャッシュが残っている場合に表示されます。
次のコマンドでLaravelのキャッシュをクリアしましょう。

php artisan cache:clear
Laravelでユーザーごとの権限を管理するlaravel-permissionをインストールする
Tagged on:                 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です