認証と認可できるところまで作る
各テナント内で、認証と認可ができるようにします。
ここで使うパッケージは、Spatieによるlaravel-permissionです。ユーザーに直接Permissionを与えたり、RoleにPermissionを与えてUserにRoleを割り当てたりできます。
laravel-permissionをインストール
先にドキュメントを読んで、何となく使い方を把握しておくと楽です。英語が読めなくても使い方の箇所を何となく見てるだけでも分かりそうです。
パッケージを入れます。
composer require spatie/laravel-permission
さて、このパッケージにマルチテナントアプリだということを教えなくてはいけません。修正対象はPermissionとRoleのModelなのですが、ただ、もちろんあとでアップデートすることも考えて、直接Modelのコードを修正するのはやめておきます。具体的には、PermissionとRoleのModelを自作して、パッケージにこれらを使うように教えることにします。これはパッケージのvendor configファイルでの設定で実現可能です。まずpublishしましょう。
php artisan vendor:publish
今回は、以下を選びます。
Provider: Spatie\Permission\PermissionServiceProvider
これにより、config/permission.php
とxxxx_xx_xx_xxxxxx_create_permission_tables.php
の2つが生成されます。
Migrationであるxxxx_xx_xx_xxxxxx_create_permission_tables.php
は、テナント用のテーブルとしなくてはいけないので、database/migrations
フォルダからdatabase/migrations/tenant
フォルダに移動します。
次に、config/permission.php
を編集します。models
セクションに以下のように追記です。(元の'permission'
と'role'
はコメントアウト)
...
'models' => [
// For Tenancy, the custom permission/role models are used.
'permission' => App\Permission::class,
'role' => App\Role::class,
...
//'permission' => Spatie\Permission\Models\Permission::class,
...
//'role' => Spatie\Permission\Models\Role::class,
...
実際にModelを作ります。
php artisan make:model Permission
php artisan make:model Role
空っぽのModelが2つできるので、ここにマルチテナントアプリであることを教えて(テナント用のデータベース接続を使わせる)、なおかつlaravel-permissionパッケージの継承を行います。
<?php
namespace App;
use Hyn\Tenancy\Traits\UsesTenantConnection;
use Spatie\Permission\Models\Permission as BasePermission;
class Permission extends BasePermission
{
use UsesTenantConnection;
}
<?php
namespace App;
use Hyn\Tenancy\Traits\UsesTenantConnection;
use Spatie\Permission\Models\Role as BaseRole;
class Role extends BaseRole
{
use UsesTenantConnection;
}
RoleとPermissionの初期設定をSeedする
テナントが作られたとき、テナントデータベースに、RoleとPermissionの初期設定をSeedしたいので、それを設定してきます。これに必要なのは、どのSeederを使うべきかを教えるだけです。config/tenancy.php
の'tenant-seed-class'
設定部分を見つけ、以下のように編集します。
...
'tenant-seed-class' => TenantDatabaseSeeder::class,
...
これにより、テナントデータベースが作られた後に'database/seeds/TenantDatabaseSeeder.php'クラスが実行されます。
Seederを作りましょう。
php artisan make:seeder TenantDatabaseSeeder
中を編集します。
<?php
use App\Permission;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Role;
class TenantDatabaseSeeder extends Seeder
{
public function run()
{
$this->addRolesAndPermissions();
}
private function addRolesAndPermissions()
{
// create permissions for an admin
$adminPermissions = collect(['create user', 'edit user', 'delete user'])->map(function ($name) {
return Permission::create(['name' => $name]);
});
// add admin role
$adminRole = Role::create(['name' => 'admin']);
$adminRole->givePermissionTo($adminPermissions);
// add a default user role
Role::create(['name' => 'user']);
}
}
ポイントとしては、['create user', 'edit user', 'delete user']
という3つのPermissionを作って、それをadminというRoleに割り当てて、さらに別途userというRoleを作っています。user Roleには何もPermissionが与えられていないですね。これらのPermissionは例なので深く考えないことにして、こんな感じで初期権限割り当てができるということだけ理解すれば十分です。
管理ユーザーにadmin権限を与える
Part1では管理ユーザーを作っただけで権限を与えていませんでしたが、ここで権限を与える処理を加えます。
ただ、その前にUserモデルがそもそもPermissionとRoleに対応しなければいけないのと、そもそもまだマルチテナント接続しなければいけないことに気づいてないので、以下のように追記編集します。
use Hyn\Tenancy\Traits\UsesTenantConnection;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use UsesTenantConnection;
use HasRoles;
// ...
}
今後作るほかのModelにも、use UsesTenantConnection;
を忘れないようにしてください。忘れるとハマります。
では、app/Console/Commands/CreateTenant.php
に権限設定コードを入れましょう。
...
private function addAdmin($name, $email, $password)
{
$admin = User::create(['name' => $name, 'email' => $email, 'password' => Hash::make($password)]);
$admin->guard_name = 'web';
$admin->assignRole('admin');
return $admin;
}
...
2行追加しました。ガードでwebを指定し、管理ユーザーに権限を付与しています。UIでこの操作を行う場合ガードは気にしなくていいで鵜が、今回はコマンドラインで実行しているので、webに対しての権限付与であることを明示します。
もう一度テナントを作ってみましょう。
php artisan tenant:create john john@example.com cafejohn
成功したらテナントのデータベースを見てみましょう。model_has_permissions
, model_has_roles
, role_has_permissions
, そして roles
のテーブルができているはずです。
今後UIを作ることになったとしても、このコマンドをまねして作れば簡単です。