背景
ロールを元にユーザーテーブルのガードを分けたかった。
実践的には、ガードを分けるよりも、一つのガードでログインした後に権限でアクセス制御したほうがいいと思う。あくまでも実験的なものとして覚え書きを残す。
動作環境
- Mac OS X 10.15.7
- Laravel 8.33.1
- Laravel Permission 4.0.0
プロジェクトの作成
Laravel-Permission の導入
composer require spatie/laravel-permission
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
モデルの作成
php artisan make:model Student -f
php artisan make:model Teacher -f
app/Models/Student.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Spatie\Permission\Traits\HasRoles;
class Student extends Model
{
use HasFactory;
use HasRoles;
protected $table = 'users';
protected $fillable = ['name', 'email', 'password'];
protected $hidden = ['password', 'remember_token'];
protected $casts = [
'email_verified_at' => 'datetime',
];
protected static function booted(): void
{
static::creating(function ($student) {
$student->assignRole('student');
});
static::addGlobalScope('role', function (Builder $builder) {
$builder->role('student');
});
}
}
app/Models/Teacher.php
namespace App\Models;
use Spatie\Permission\Traits\HasRoles;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Teacher extends Model
{
use HasFactory;
use HasRoles;
protected $table = 'users';
protected $fillable = ['name', 'email', 'password'];
protected $hidden = ['password', 'remember_token'];
protected $casts = [
'email_verified_at' => 'datetime',
];
protected static function booted(): void
{
static::creating(function ($teacher) {
$teacher->assignRole('teacher');
});
static::addGlobalScope('role', function (Builder $builder) {
$builder->role('teacher');
});
}
}
User
に書いてそれぞれ継承でもいいと思う。
ガードの設定
プロパイダーの設定を auth.providers
に追記する。
'students' => [
'driver' => 'eloquent',
'model' => App\Models\Student::class,
],
'teachers' => [
'driver' => 'eloquent',
'model' => App\Models\Teacher::class,
],
ガードの設定を auth.guards
に追記する。
'student' => [
'driver' => 'session',
'provider' => 'students',
],
'teacher' => [
'driver' => 'session',
'provider' => 'teachers',
],
ファクトリの作成
UserFactory
の definition()
をコピーして、StudentFactory
と TeacherFactory
を用意する。
ロールの投入
マイグレーションして、Role
を用意する。
php artisan migrate
php artisan permission:create-role student student
php artisan permission:create-role teacher teacher
動作確認
Tinker
で動作確認する。
php artisan tinker
Student
, Teacher
を作成して、それぞれ別々に取得できるのを確かめる。
Student::factory(3)->create();
Teacher::factory(3)->create();
Student::all();
Teacher::all();
補足:ガードを追加したくない場合
Laravel-Permission
はガードに紐づいているプロバイダーの model
を元にロールを絞り込む。
ガードを新たに追加しなくても、モデルに public function guardName()
か protected $guard_name
を明示すると特定のガードを流用できる。
この方法を選んだ場合、「ロールの投入」でも第二引数の guard_name
を合わせること。
参考資料
- https://readouble.com/laravel/8.x/ja/eloquent.html#anonymous-global-scopes
- https://readouble.com/laravel/8.x/ja/eloquent.html#events-using-closures
- https://spatie.be/docs/laravel-permission/v3/basic-usage/basic-usage
- https://spatie.be/docs/laravel-permission/v3/basic-usage/multiple-guards
- https://qiita.com/kd9951/items/c4e5526a6feb4437d1f0