-- 修复当前海外环境平台管理员的安全投影。 -- 适用数据库:baiyue_iam、baiyue_lastleg;脚本可重复执行。 USE baiyue_lastleg; -- 旧环境可能缺少角色或权限快照列;先保证两列都存在。 SET @ddl = ( SELECT IF(COUNT(*) = 0, 'ALTER TABLE ll_security_projection ADD COLUMN roles_json JSON NULL COMMENT ''IAM投影的当前角色快照'' AFTER permission_version', 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_security_projection' AND column_name = 'roles_json' ); PREPARE security_projection_roles_ddl FROM @ddl; EXECUTE security_projection_roles_ddl; DEALLOCATE PREPARE security_projection_roles_ddl; SET @ddl = ( SELECT IF(COUNT(*) = 0, 'ALTER TABLE ll_security_projection ADD COLUMN authorities_json JSON NULL AFTER roles_json', 'SELECT 1') FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'll_security_projection' AND column_name = 'authorities_json' ); PREPARE security_projection_ddl FROM @ddl; EXECUTE security_projection_ddl; DEALLOCATE PREPARE security_projection_ddl; UPDATE ll_security_projection SET roles_json = JSON_ARRAY() WHERE roles_json IS NULL; UPDATE ll_security_projection SET authorities_json = JSON_ARRAY() WHERE authorities_json IS NULL; -- 从 IAM 当前平台成员重建 USER 与 AUTHORIZATION 投影,避免把修复绑定到某个环境账号 ID。 INSERT INTO ll_security_projection ( aggregate_type, aggregate_id, tenant_id, security_status, permission_version, roles_json, authorities_json, aggregate_version, payload_hash, last_event_id, changed_at, updated_at ) SELECT 'USER', CAST(u.auth_user_id AS CHAR), 0, IF(u.status = 'ACTIVE' AND m.status = 'ACTIVE', 'ACTIVE', 'DISABLED'), COALESCE(v.permission_version, 0), JSON_ARRAY(), JSON_ARRAY(), COALESCE(v.permission_version, 0), SHA2(CONCAT('environment-repair:', u.auth_user_id, ':user:', COALESCE(v.permission_version, 0)), 256), CONCAT('repair-', u.auth_user_id, '-u-', DATE_FORMAT(NOW(3), '%Y%m%d%H%i%s%f')), NOW(3), NOW(3) FROM baiyue_iam.iam_user u JOIN baiyue_iam.iam_membership m ON m.user_id = u.id AND m.tenant_id = 0 AND m.deleted = 0 LEFT JOIN baiyue_iam.iam_security_subject_version v ON v.auth_user_id = u.auth_user_id WHERE u.auth_user_id IS NOT NULL AND u.deleted = 0 AND EXISTS ( SELECT 1 FROM baiyue_iam.iam_membership_role mr JOIN baiyue_iam.iam_role r ON r.id = mr.role_id WHERE mr.membership_id = m.id AND mr.tenant_id = m.tenant_id AND r.app_code = 'PLATFORM' AND r.status = 'ACTIVE' AND r.deleted = 0 ) ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id), security_status = VALUES(security_status), permission_version = VALUES(permission_version), aggregate_version = VALUES(aggregate_version), payload_hash = VALUES(payload_hash), last_event_id = VALUES(last_event_id), changed_at = VALUES(changed_at), updated_at = NOW(3); INSERT INTO ll_security_projection ( aggregate_type, aggregate_id, tenant_id, security_status, permission_version, roles_json, authorities_json, aggregate_version, payload_hash, last_event_id, changed_at, updated_at ) SELECT 'AUTHORIZATION', CAST(u.auth_user_id AS CHAR), 0, NULL, COALESCE(v.permission_version, 0), COALESCE(( SELECT JSON_ARRAYAGG(r2.role_code) FROM baiyue_iam.iam_user u2 JOIN baiyue_iam.iam_membership m2 ON m2.user_id = u2.id JOIN baiyue_iam.iam_membership_role mr2 ON mr2.membership_id = m2.id AND mr2.tenant_id = m2.tenant_id JOIN baiyue_iam.iam_role r2 ON r2.id = mr2.role_id WHERE u2.auth_user_id = u.auth_user_id AND m2.tenant_id = 0 AND m2.status = 'ACTIVE' AND m2.deleted = 0 AND r2.app_code = 'PLATFORM' AND r2.status = 'ACTIVE' AND r2.deleted = 0 ), JSON_ARRAY()), COALESCE(( SELECT JSON_ARRAYAGG(p2.permission_code) FROM baiyue_iam.iam_user u2 JOIN baiyue_iam.iam_membership m2 ON m2.user_id = u2.id JOIN baiyue_iam.iam_membership_role mr2 ON mr2.membership_id = m2.id AND mr2.tenant_id = m2.tenant_id JOIN baiyue_iam.iam_role r2 ON r2.id = mr2.role_id JOIN baiyue_iam.iam_role_permission rp2 ON rp2.role_id = r2.id AND rp2.tenant_id = r2.tenant_id JOIN baiyue_iam.iam_permission p2 ON p2.id = rp2.permission_id AND p2.tenant_id = rp2.tenant_id WHERE u2.auth_user_id = u.auth_user_id AND m2.tenant_id = 0 AND m2.status = 'ACTIVE' AND m2.deleted = 0 AND r2.app_code = 'PLATFORM' AND r2.status = 'ACTIVE' AND r2.deleted = 0 AND p2.app_code = 'PLATFORM' AND p2.status = 'ACTIVE' AND p2.deleted = 0 AND (p2.permission_code LIKE 'platform:overseas-warehouse:%' OR p2.permission_code LIKE 'platform:overseas-business:%' OR p2.permission_code LIKE 'platform:overseas-master-data:%' OR p2.permission_code LIKE 'platform:finance:%' OR p2.permission_code LIKE 'lastleg:%') ), JSON_ARRAY()), COALESCE(v.permission_version, 0), SHA2(CONCAT('environment-repair:', u.auth_user_id, ':authorization:', COALESCE(v.permission_version, 0)), 256), CONCAT('repair-', u.auth_user_id, '-a-', DATE_FORMAT(NOW(3), '%Y%m%d%H%i%s%f')), NOW(3), NOW(3) FROM baiyue_iam.iam_user u JOIN baiyue_iam.iam_membership m ON m.user_id = u.id AND m.tenant_id = 0 AND m.status = 'ACTIVE' AND m.deleted = 0 LEFT JOIN baiyue_iam.iam_security_subject_version v ON v.auth_user_id = u.auth_user_id WHERE u.auth_user_id IS NOT NULL AND u.status = 'ACTIVE' AND u.deleted = 0 AND EXISTS ( SELECT 1 FROM baiyue_iam.iam_membership_role mr JOIN baiyue_iam.iam_role r ON r.id = mr.role_id WHERE mr.membership_id = m.id AND mr.tenant_id = m.tenant_id AND r.app_code = 'PLATFORM' AND r.status = 'ACTIVE' AND r.deleted = 0 ) ON DUPLICATE KEY UPDATE tenant_id = VALUES(tenant_id), permission_version = VALUES(permission_version), roles_json = VALUES(roles_json), authorities_json = VALUES(authorities_json), aggregate_version = VALUES(aggregate_version), payload_hash = VALUES(payload_hash), last_event_id = VALUES(last_event_id), changed_at = VALUES(changed_at), updated_at = NOW(3); SELECT aggregate_type, aggregate_id, tenant_id, permission_version, JSON_LENGTH(roles_json) AS role_count, JSON_LENGTH(authorities_json) AS authority_count, updated_at FROM ll_security_projection WHERE tenant_id = 0 AND aggregate_type IN ('USER', 'AUTHORIZATION') ORDER BY CAST(aggregate_id AS UNSIGNED), aggregate_type;