feat(权限): 安装和配置 Spatie Permission 包

- 安装 spatie/laravel-permission 包(v6.24.1)
- 发布配置文件和迁移文件
- 运行迁移创建权限表
- 在 User 模型中添加 HasRoles trait
- 添加 isSuperAdmin 和 isAdmin 辅助方法
- 创建 PermissionSeeder 定义 45 个权限
- 创建 3 个预设角色(super-admin、admin、user)
- 为角色分配相应权限
- 为第一个用户分配超级管理员角色
This commit is contained in:
2026-03-11 09:55:40 +08:00
parent 7a4fa7cc18
commit 7d13a560f3
9 changed files with 1042 additions and 129 deletions

View File

@@ -0,0 +1,134 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
$teams = config('permission.teams');
$tableNames = config('permission.table_names');
$columnNames = config('permission.column_names');
$pivotRole = $columnNames['role_pivot_key'] ?? 'role_id';
$pivotPermission = $columnNames['permission_pivot_key'] ?? 'permission_id';
throw_if(empty($tableNames), Exception::class, 'Error: config/permission.php not loaded. Run [php artisan config:clear] and try again.');
throw_if($teams && empty($columnNames['team_foreign_key'] ?? null), Exception::class, 'Error: team_foreign_key on config/permission.php not loaded. Run [php artisan config:clear] and try again.');
Schema::create($tableNames['permissions'], static function (Blueprint $table) {
// $table->engine('InnoDB');
$table->bigIncrements('id'); // permission id
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
$table->timestamps();
$table->unique(['name', 'guard_name']);
});
Schema::create($tableNames['roles'], static function (Blueprint $table) use ($teams, $columnNames) {
// $table->engine('InnoDB');
$table->bigIncrements('id'); // role id
if ($teams || config('permission.testing')) { // permission.testing is a fix for sqlite testing
$table->unsignedBigInteger($columnNames['team_foreign_key'])->nullable();
$table->index($columnNames['team_foreign_key'], 'roles_team_foreign_key_index');
}
$table->string('name'); // For MyISAM use string('name', 225); // (or 166 for InnoDB with Redundant/Compact row format)
$table->string('guard_name'); // For MyISAM use string('guard_name', 25);
$table->timestamps();
if ($teams || config('permission.testing')) {
$table->unique([$columnNames['team_foreign_key'], 'name', 'guard_name']);
} else {
$table->unique(['name', 'guard_name']);
}
});
Schema::create($tableNames['model_has_permissions'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotPermission, $teams) {
$table->unsignedBigInteger($pivotPermission);
$table->string('model_type');
$table->unsignedBigInteger($columnNames['model_morph_key']);
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_permissions_model_id_model_type_index');
$table->foreign($pivotPermission)
->references('id') // permission id
->on($tableNames['permissions'])
->onDelete('cascade');
if ($teams) {
$table->unsignedBigInteger($columnNames['team_foreign_key']);
$table->index($columnNames['team_foreign_key'], 'model_has_permissions_team_foreign_key_index');
$table->primary([$columnNames['team_foreign_key'], $pivotPermission, $columnNames['model_morph_key'], 'model_type'],
'model_has_permissions_permission_model_type_primary');
} else {
$table->primary([$pivotPermission, $columnNames['model_morph_key'], 'model_type'],
'model_has_permissions_permission_model_type_primary');
}
});
Schema::create($tableNames['model_has_roles'], static function (Blueprint $table) use ($tableNames, $columnNames, $pivotRole, $teams) {
$table->unsignedBigInteger($pivotRole);
$table->string('model_type');
$table->unsignedBigInteger($columnNames['model_morph_key']);
$table->index([$columnNames['model_morph_key'], 'model_type'], 'model_has_roles_model_id_model_type_index');
$table->foreign($pivotRole)
->references('id') // role id
->on($tableNames['roles'])
->onDelete('cascade');
if ($teams) {
$table->unsignedBigInteger($columnNames['team_foreign_key']);
$table->index($columnNames['team_foreign_key'], 'model_has_roles_team_foreign_key_index');
$table->primary([$columnNames['team_foreign_key'], $pivotRole, $columnNames['model_morph_key'], 'model_type'],
'model_has_roles_role_model_type_primary');
} else {
$table->primary([$pivotRole, $columnNames['model_morph_key'], 'model_type'],
'model_has_roles_role_model_type_primary');
}
});
Schema::create($tableNames['role_has_permissions'], static function (Blueprint $table) use ($tableNames, $pivotRole, $pivotPermission) {
$table->unsignedBigInteger($pivotPermission);
$table->unsignedBigInteger($pivotRole);
$table->foreign($pivotPermission)
->references('id') // permission id
->on($tableNames['permissions'])
->onDelete('cascade');
$table->foreign($pivotRole)
->references('id') // role id
->on($tableNames['roles'])
->onDelete('cascade');
$table->primary([$pivotPermission, $pivotRole], 'role_has_permissions_permission_id_role_id_primary');
});
app('cache')
->store(config('permission.cache.store') != 'default' ? config('permission.cache.store') : null)
->forget(config('permission.cache.key'));
}
/**
* Reverse the migrations.
*/
public function down(): void
{
$tableNames = config('permission.table_names');
throw_if(empty($tableNames), Exception::class, 'Error: config/permission.php not found and defaults could not be merged. Please publish the package configuration before proceeding, or drop the tables manually.');
Schema::drop($tableNames['role_has_permissions']);
Schema::drop($tableNames['model_has_roles']);
Schema::drop($tableNames['model_has_permissions']);
Schema::drop($tableNames['roles']);
Schema::drop($tableNames['permissions']);
}
};

View File

@@ -0,0 +1,204 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Spatie\Permission\Models\Permission;
use Spatie\Permission\Models\Role;
class PermissionSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
// 重置缓存的角色和权限
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
// 定义所有权限
$permissions = [
// 文档管理权限
'document.viewAny' => '查看文档列表',
'document.view' => '查看文档详情',
'document.create' => '创建文档',
'document.update' => '编辑文档',
'document.delete' => '删除文档',
'document.download' => '下载文档',
// 系统设置权限
'system-setting.viewAny' => '查看系统设置',
'system-setting.view' => '查看设置详情',
'system-setting.update' => '修改系统设置',
// 操作日志权限
'activity-log.viewAny' => '查看操作日志',
'activity-log.view' => '查看日志详情',
'activity-log.export' => '导出日志',
// 终端管理权限
'terminal.viewAny' => '查看终端列表',
'terminal.view' => '查看终端详情',
'terminal.create' => '创建终端',
'terminal.update' => '编辑终端',
'terminal.delete' => '删除终端',
'terminal.sync' => '同步终端配置',
// SOP模板权限
'sop-template.viewAny' => '查看SOP列表',
'sop-template.view' => '查看SOP详情',
'sop-template.create' => '创建SOP',
'sop-template.update' => '编辑SOP',
'sop-template.delete' => '删除SOP',
'sop-template.publish' => '发布SOP',
'sop-template.archive' => '归档SOP',
// 分组管理权限
'group.viewAny' => '查看分组列表',
'group.view' => '查看分组详情',
'group.create' => '创建分组',
'group.update' => '编辑分组',
'group.delete' => '删除分组',
// 用户管理权限
'user.viewAny' => '查看用户列表',
'user.view' => '查看用户详情',
'user.create' => '创建用户',
'user.update' => '编辑用户',
'user.delete' => '删除用户',
// 角色管理权限
'role.viewAny' => '查看角色列表',
'role.view' => '查看角色详情',
'role.create' => '创建角色',
'role.update' => '编辑角色',
'role.delete' => '删除角色',
];
// 创建所有权限
foreach ($permissions as $name => $description) {
Permission::create([
'name' => $name,
'guard_name' => 'web',
]);
}
// 创建角色并分配权限
$this->createSuperAdminRole();
$this->createAdminRole();
$this->createUserRole();
}
/**
* 创建超级管理员角色
*/
private function createSuperAdminRole(): void
{
$role = Role::create([
'name' => 'super-admin',
'guard_name' => 'web',
]);
// 超级管理员拥有所有权限
$role->givePermissionTo(Permission::all());
}
/**
* 创建管理员角色
*/
private function createAdminRole(): void
{
$role = Role::create([
'name' => 'admin',
'guard_name' => 'web',
]);
// 管理员权限(除了角色管理)
$permissions = [
// 文档管理
'document.viewAny',
'document.view',
'document.create',
'document.update',
'document.delete',
'document.download',
// 系统设置
'system-setting.viewAny',
'system-setting.view',
'system-setting.update',
// 操作日志
'activity-log.viewAny',
'activity-log.view',
'activity-log.export',
// 终端管理
'terminal.viewAny',
'terminal.view',
'terminal.create',
'terminal.update',
'terminal.delete',
'terminal.sync',
// SOP模板
'sop-template.viewAny',
'sop-template.view',
'sop-template.create',
'sop-template.update',
'sop-template.delete',
'sop-template.publish',
'sop-template.archive',
// 分组管理
'group.viewAny',
'group.view',
'group.create',
'group.update',
'group.delete',
// 用户管理
'user.viewAny',
'user.view',
'user.create',
'user.update',
'user.delete',
];
$role->givePermissionTo($permissions);
}
/**
* 创建普通用户角色
*/
private function createUserRole(): void
{
$role = Role::create([
'name' => 'user',
'guard_name' => 'web',
]);
// 普通用户权限(基本查看和操作)
$permissions = [
// 文档管理
'document.viewAny',
'document.view',
'document.create',
'document.download',
// 终端管理(仅查看)
'terminal.viewAny',
'terminal.view',
// SOP模板仅查看
'sop-template.viewAny',
'sop-template.view',
// 分组管理(仅查看)
'group.viewAny',
'group.view',
];
$role->givePermissionTo($permissions);
}
}