feat: 增强管理员权限与角色管理功能
- 在 SyncAdminAuthorizationCommand 中新增对代理和抽奖菜单操作的同步功能,确保缺失的菜单操作行能够被创建。 - 更新多个控制器中的权限检查逻辑,使用 hasPermissionCode 替代原有的权限验证方式,提升权限管理的灵活性。 - 引入 ApiMessage 统一错误响应格式,确保在权限不足时返回一致的错误信息。 - 更新 AdminRole 和 AdminUser 模型,增强角色与用户的权限管理功能,支持更细粒度的权限控制。
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
/**
|
||||
* 代理「节点 / 角色 / 账号」查看与管理拆分为独立 permission_code,避免只勾一项却获得全部管理能力。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$now = Carbon::now();
|
||||
$viewActionId = DB::table('admin_action_catalog')->where('code', 'view')->value('id');
|
||||
$manageActionId = DB::table('admin_action_catalog')->where('code', 'manage')->value('id');
|
||||
if ($viewActionId === null || $manageActionId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$agentMenuId = (int) DB::table('admin_menus')->where('code', 'system.agents')->value('id');
|
||||
if ($agentMenuId === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rolesMenuId = $this->ensureChildMenu($agentMenuId, 'system.agents.roles', '代理角色', $now);
|
||||
$usersMenuId = $this->ensureChildMenu($agentMenuId, 'system.agents.users', '代理账号', $now);
|
||||
|
||||
$this->ensureMenuAction((int) $rolesMenuId, (int) $viewActionId, 'agent.role.view', '代理角色查看', $now);
|
||||
$this->ensureMenuAction((int) $rolesMenuId, (int) $manageActionId, 'agent.role.manage', '代理角色管理', $now);
|
||||
$this->ensureMenuAction((int) $usersMenuId, (int) $viewActionId, 'agent.user.view', '代理账号查看', $now);
|
||||
$this->ensureMenuAction((int) $usersMenuId, (int) $manageActionId, 'agent.user.manage', '代理账号管理', $now);
|
||||
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
$nodeViewId = $menuActionIds['agent.node.view'] ?? null;
|
||||
$nodeManageId = $menuActionIds['agent.node.manage'] ?? null;
|
||||
$roleViewId = $menuActionIds['agent.role.view'] ?? null;
|
||||
$roleManageId = $menuActionIds['agent.role.manage'] ?? null;
|
||||
$userViewId = $menuActionIds['agent.user.view'] ?? null;
|
||||
$userManageId = $menuActionIds['agent.user.manage'] ?? null;
|
||||
|
||||
if ($nodeViewId !== null && $roleViewId !== null && $userViewId !== null) {
|
||||
$roleIdsWithNodeView = DB::table('admin_role_menu_actions')
|
||||
->where('menu_action_id', (int) $nodeViewId)
|
||||
->pluck('role_id')
|
||||
->unique()
|
||||
->all();
|
||||
|
||||
foreach ($roleIdsWithNodeView as $roleId) {
|
||||
foreach ([$roleViewId, $userViewId] as $actionId) {
|
||||
$this->attachRoleMenuAction((int) $roleId, (int) $actionId, $now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($nodeManageId !== null && $roleManageId !== null && $userManageId !== null) {
|
||||
$roleIdsWithNodeManage = DB::table('admin_role_menu_actions')
|
||||
->where('menu_action_id', (int) $nodeManageId)
|
||||
->pluck('role_id')
|
||||
->unique()
|
||||
->all();
|
||||
|
||||
foreach ($roleIdsWithNodeManage as $roleId) {
|
||||
foreach ([$roleManageId, $userManageId] as $actionId) {
|
||||
$this->attachRoleMenuAction((int) $roleId, (int) $actionId, $now);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$resources = array_values(array_filter(
|
||||
AdminAuthorizationRegistry::resources(),
|
||||
static fn (array $resource): bool => str_starts_with((string) $resource['code'], 'admin.agent-')
|
||||
));
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$resourceId = DB::table('admin_api_resources')->where('code', $resource['code'])->value('id');
|
||||
if ($resourceId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] ?? [] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function ensureChildMenu(int $parentId, string $code, string $name, Carbon $now): int
|
||||
{
|
||||
$existing = DB::table('admin_menus')->where('code', $code)->value('id');
|
||||
if ($existing !== null) {
|
||||
return (int) $existing;
|
||||
}
|
||||
|
||||
return (int) DB::table('admin_menus')->insertGetId([
|
||||
'parent_id' => $parentId,
|
||||
'menu_type' => 'button',
|
||||
'code' => $code,
|
||||
'name' => $name,
|
||||
'path' => null,
|
||||
'route_name' => null,
|
||||
'component' => null,
|
||||
'icon' => null,
|
||||
'active_menu_code' => 'system.agents',
|
||||
'sort_order' => 0,
|
||||
'is_visible' => false,
|
||||
'is_cache' => false,
|
||||
'is_external' => false,
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
private function ensureMenuAction(int $menuId, int $actionId, string $permissionCode, string $name, Carbon $now): void
|
||||
{
|
||||
if (DB::table('admin_menu_actions')->where('permission_code', $permissionCode)->exists()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_menu_actions')->insert([
|
||||
'menu_id' => $menuId,
|
||||
'action_id' => $actionId,
|
||||
'permission_code' => $permissionCode,
|
||||
'name' => $name,
|
||||
'status' => 1,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
|
||||
private function attachRoleMenuAction(int $roleId, int $menuActionId, Carbon $now): void
|
||||
{
|
||||
$exists = DB::table('admin_role_menu_actions')
|
||||
->where('role_id', $roleId)
|
||||
->where('menu_action_id', $menuActionId)
|
||||
->exists();
|
||||
|
||||
if ($exists) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_role_menu_actions')->insert([
|
||||
'role_id' => $roleId,
|
||||
'menu_action_id' => $menuActionId,
|
||||
]);
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$codes = ['agent.role.view', 'agent.role.manage', 'agent.user.view', 'agent.user.manage'];
|
||||
$actionIds = DB::table('admin_menu_actions')->whereIn('permission_code', $codes)->pluck('id')->all();
|
||||
|
||||
if ($actionIds !== []) {
|
||||
DB::table('admin_role_menu_actions')->whereIn('menu_action_id', $actionIds)->delete();
|
||||
DB::table('admin_api_resource_bindings')->whereIn('menu_action_id', $actionIds)->delete();
|
||||
DB::table('admin_menu_actions')->whereIn('permission_code', $codes)->delete();
|
||||
}
|
||||
|
||||
DB::table('admin_menus')->whereIn('code', ['system.agents.roles', 'system.agents.users'])->delete();
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
use App\Support\AdminAuthorizationRegistry;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
/** 补齐代理账号删除 API 资源(admin.agent-admin-users.destroy)。 */
|
||||
return new class extends Migration
|
||||
{
|
||||
private const RESOURCE_CODE = 'admin.agent-admin-users.destroy';
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$resource = collect(AdminAuthorizationRegistry::resources())
|
||||
->firstWhere('code', self::RESOURCE_CODE);
|
||||
|
||||
if ($resource === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$now = Carbon::now();
|
||||
$menuActionIds = DB::table('admin_menu_actions')->pluck('id', 'permission_code');
|
||||
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', self::RESOURCE_CODE)
|
||||
->value('id');
|
||||
|
||||
$payload = [
|
||||
'module_code' => $resource['module_code'],
|
||||
'name' => $resource['name'],
|
||||
'http_method' => $resource['http_method'],
|
||||
'uri_pattern' => $resource['uri_pattern'],
|
||||
'route_name' => $resource['route_name'],
|
||||
'auth_mode' => $resource['auth_mode'],
|
||||
'is_audit_required' => $resource['is_audit_required'],
|
||||
'status' => 1,
|
||||
'meta_json' => null,
|
||||
'updated_at' => $now,
|
||||
];
|
||||
|
||||
if ($resourceId === null) {
|
||||
$resourceId = DB::table('admin_api_resources')->insertGetId($payload + [
|
||||
'code' => self::RESOURCE_CODE,
|
||||
'created_at' => $now,
|
||||
]);
|
||||
} else {
|
||||
DB::table('admin_api_resources')
|
||||
->where('id', (int) $resourceId)
|
||||
->update($payload);
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
|
||||
foreach ($resource['permission_codes'] as $permissionCode) {
|
||||
$menuActionId = $menuActionIds[$permissionCode] ?? null;
|
||||
if ($menuActionId === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')->insert([
|
||||
'api_resource_id' => (int) $resourceId,
|
||||
'menu_action_id' => (int) $menuActionId,
|
||||
'created_at' => $now,
|
||||
'updated_at' => $now,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$resourceId = DB::table('admin_api_resources')
|
||||
->where('code', self::RESOURCE_CODE)
|
||||
->value('id');
|
||||
|
||||
if ($resourceId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::table('admin_api_resource_bindings')
|
||||
->where('api_resource_id', (int) $resourceId)
|
||||
->delete();
|
||||
DB::table('admin_api_resources')->where('id', (int) $resourceId)->delete();
|
||||
}
|
||||
};
|
||||
@@ -5,6 +5,8 @@ namespace Database\Seeders;
|
||||
use App\Models\AdminRole;
|
||||
use App\Models\AdminUser;
|
||||
use Illuminate\Database\Seeder;
|
||||
use App\Support\AdminAgentPermissionMenuActionSync;
|
||||
use App\Support\AdminDrawPermissionMenuActionSync;
|
||||
use App\Support\AdminPermissionBridge;
|
||||
|
||||
/**
|
||||
@@ -28,6 +30,9 @@ final class AdminRbacAndUserSeeder extends Seeder
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
AdminAgentPermissionMenuActionSync::syncMissing();
|
||||
AdminDrawPermissionMenuActionSync::syncMissing();
|
||||
|
||||
$super = AdminRole::query()->updateOrCreate(
|
||||
['slug' => AdminUser::ROLE_SUPER_ADMIN],
|
||||
['code' => AdminUser::ROLE_SUPER_ADMIN, 'name' => '超级管理员'],
|
||||
|
||||
Reference in New Issue
Block a user