feat(admin): 更新后台权限管理与同步逻辑,简化权限检查并优化文档
- 新增后台 RBAC 相关文档,提供权限目录与维护命令说明。 - 移除不必要的角色资源同步检查,简化权限审计命令。 - 更新权限描述与同步逻辑,确保一致性与可维护性。 - 统一权限注册表,替换过时的权限别名,增强代码可读性。
This commit is contained in:
@@ -11,10 +11,9 @@ final class AuditAdminAuthorizationCommand extends Command
|
||||
{
|
||||
protected $signature = 'lottery:admin-auth-audit
|
||||
{--skip-route-coverage : 跳过受保护后台路由是否已注册 API 资源的检查}
|
||||
{--skip-resource-bindings : 跳过 permission_required 资源是否绑定动作权限的检查}
|
||||
{--skip-role-resource-sync : 跳过 role_menu_actions 与 role_api_resources 一致性检查}';
|
||||
{--skip-resource-bindings : 跳过 permission_required 资源是否绑定动作权限的检查}';
|
||||
|
||||
protected $description = '检查后台权限配置是否存在路由覆盖缺失、资源绑定缺失或角色资源漂移';
|
||||
protected $description = '检查后台权限配置是否存在路由覆盖缺失或资源绑定缺失';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
@@ -28,10 +27,6 @@ final class AuditAdminAuthorizationCommand extends Command
|
||||
$issues = array_merge($issues, $this->checkPermissionResourceBindings());
|
||||
}
|
||||
|
||||
if (! (bool) $this->option('skip-role-resource-sync')) {
|
||||
$issues = array_merge($issues, $this->checkRoleApiResourceSync());
|
||||
}
|
||||
|
||||
if ($issues === []) {
|
||||
$this->info('Admin authorization audit passed.');
|
||||
|
||||
@@ -116,70 +111,6 @@ final class AuditAdminAuthorizationCommand extends Command
|
||||
return $issues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{type: string, message: string}>
|
||||
*/
|
||||
private function checkRoleApiResourceSync(): array
|
||||
{
|
||||
$expectedRows = DB::table('admin_role_menu_actions as rma')
|
||||
->join('admin_api_resource_bindings as arb', 'arb.menu_action_id', '=', 'rma.menu_action_id')
|
||||
->select('rma.role_id', 'arb.api_resource_id')
|
||||
->distinct()
|
||||
->get();
|
||||
|
||||
$expectedSet = [];
|
||||
foreach ($expectedRows as $row) {
|
||||
$expectedSet[$this->roleApiKey((int) $row->role_id, (int) $row->api_resource_id)] = true;
|
||||
}
|
||||
|
||||
$actualRows = DB::table('admin_role_api_resources')
|
||||
->select('role_id', 'api_resource_id')
|
||||
->get();
|
||||
|
||||
$actualSet = [];
|
||||
foreach ($actualRows as $row) {
|
||||
$actualSet[$this->roleApiKey((int) $row->role_id, (int) $row->api_resource_id)] = true;
|
||||
}
|
||||
|
||||
$roleSlugs = DB::table('admin_roles')->pluck('slug', 'id')->all();
|
||||
$resourceCodes = DB::table('admin_api_resources')->pluck('code', 'id')->all();
|
||||
$issues = [];
|
||||
|
||||
foreach (array_keys($expectedSet) as $key) {
|
||||
if (isset($actualSet[$key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[$roleId, $resourceId] = array_map('intval', explode(':', $key, 2));
|
||||
$issues[] = [
|
||||
'type' => 'role_resource_sync',
|
||||
'message' => sprintf(
|
||||
'Missing role-resource grant: role `%s` should include API resource `%s`.',
|
||||
(string) ($roleSlugs[$roleId] ?? $roleId),
|
||||
(string) ($resourceCodes[$resourceId] ?? $resourceId),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
foreach (array_keys($actualSet) as $key) {
|
||||
if (isset($expectedSet[$key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[$roleId, $resourceId] = array_map('intval', explode(':', $key, 2));
|
||||
$issues[] = [
|
||||
'type' => 'role_resource_sync',
|
||||
'message' => sprintf(
|
||||
'Extra role-resource grant: role `%s` has API resource `%s` without any supporting action binding.',
|
||||
(string) ($roleSlugs[$roleId] ?? $roleId),
|
||||
(string) ($resourceCodes[$resourceId] ?? $resourceId),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
return $issues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<array{name: string, method: string, uri: string}>
|
||||
*/
|
||||
@@ -222,9 +153,4 @@ final class AuditAdminAuthorizationCommand extends Command
|
||||
{
|
||||
return preg_replace('/^(api\.v1\.admin\.)+/', 'api.v1.admin.', $routeName) ?? $routeName;
|
||||
}
|
||||
|
||||
private function roleApiKey(int $roleId, int $apiResourceId): string
|
||||
{
|
||||
return $roleId.':'.$apiResourceId;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user