Files
Migu2.0/MiGu.Server/Controllers/MapsContentController.cs
T
zhaowei.huang 20f98db6da fix(platform): 代码审查整改——反代按域拆分授权、根除探测副作用与死代码清理
- YARP: map-edit/ai-config 全方法、reflection 写方法挂 PlatformScope,
  reflection/selection 单独放行(运营端 3D 高亮),堵住运营账号直达地图编辑/反射调用
- goto-site 探测改用不存在的 car/-1(消除健康检查真实派车风险)并加 60s 缓存
- Config PUT 按 scope 收紧:RCSMonitor 仅可写 ops 节;wizard 写操作与
  simplelite/restart-for-update 限 PlatformScope;/api/health 去除虚假端口表
- 修复 wms 模块菜单裁剪失效(admin-config-location → admin-config-facility)
- vrHost 默认 location.hostname:8223(新增 utils/vrender.ts),远程访问 3D 视口可用
- /status 页改接真实 /api/health* 诊断;uploadAsset 移除矛盾 multipart 头;
  mapsApi.merge 对齐 save 的 409 冲突处理;JWT 验签参数改启动期 DI 一次性配置
- 清理死代码:ProjectionController、DataTablePro、useClipboard、CadToolbarView、
  AppShell 未用导入;lint 脚本替换为 typecheck;日志窗口 List 改 Queue
2026-06-12 23:00:47 +08:00

109 lines
4.2 KiB
C#

using System.Text.Json;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using MiGu.Server.Auth;
using MiGu.Server.Launcher;
namespace MiGu.Server.Controllers;
/// <summary>
/// 读取 SimpleLite 地图固定目录下的 JSON 原文,供平台「地图管理」右侧预览。
/// 先向 SimpleLite 拉取 maps 列表拿到 directory,再读本机同路径文件(与 SimpleLite 同机部署)。
/// </summary>
[ApiController]
[Authorize]
[Route("api/maps")]
public class MapsContentController : ControllerBase
{
private readonly IHttpClientFactory _httpFactory;
private readonly InternalTokenStore _internalToken;
private readonly SimpleLiteOptions _sl;
private readonly ILogger<MapsContentController> _log;
public MapsContentController(
IHttpClientFactory httpFactory,
InternalTokenStore internalToken,
IOptions<SimpleLiteOptions> sl,
ILogger<MapsContentController> log)
{
_httpFactory = httpFactory;
_internalToken = internalToken;
_sl = sl.Value;
_log = log;
}
[HttpGet("{name}/content")]
public async Task<IActionResult> GetContent(string name, CancellationToken ct)
{
if (string.IsNullOrWhiteSpace(name)
|| name.Contains("..", StringComparison.Ordinal)
|| name.IndexOfAny(['/', '\\', ':', '*', '?', '"', '<', '>', '|']) >= 0)
{
return BadRequest(new { message = "地图名称非法" });
}
try
{
var directory = await FetchMapsDirectoryAsync(ct);
if (string.IsNullOrWhiteSpace(directory))
return StatusCode(503, new { message = "无法从 SimpleLite 获取地图目录" });
var fileName = name.EndsWith(".json", StringComparison.OrdinalIgnoreCase) ? name : $"{name}.json";
var fullPath = Path.GetFullPath(Path.Combine(directory, fileName));
var root = Path.GetFullPath(directory);
if (!fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase))
return BadRequest(new { message = "路径校验失败" });
if (!System.IO.File.Exists(fullPath))
return NotFound(new { message = $"地图文件不存在:{fileName}" });
var content = await System.IO.File.ReadAllTextAsync(fullPath, ct);
// 不返回 fullPath:避免向前端泄露服务器目录结构。
return Ok(new
{
name,
fileName,
content
});
}
catch (Exception ex)
{
_log.LogWarning(ex, "读取地图 JSON 失败 name={Name}", name);
return StatusCode(500, new { message = $"读取地图 JSON 失败:{ex.Message}" });
}
}
private async Task<string?> FetchMapsDirectoryAsync(CancellationToken ct)
{
var client = _httpFactory.CreateClient();
client.Timeout = TimeSpan.FromSeconds(8);
var url = $"http://127.0.0.1:{_sl.ProjectionPort}/projection/map-edit/maps";
using var msg = new HttpRequestMessage(HttpMethod.Get, url);
if (!string.IsNullOrEmpty(_internalToken.Token))
msg.Headers.TryAddWithoutValidation("X-Platform-Internal-Token", _internalToken.Token);
using var resp = await client.SendAsync(msg, ct);
var body = await resp.Content.ReadAsStringAsync(ct);
if (!resp.IsSuccessStatusCode)
throw new InvalidOperationException($"SimpleLite maps 列表返回 {(int)resp.StatusCode}");
using var doc = JsonDocument.Parse(body);
var root = doc.RootElement;
if (root.TryGetProperty("success", out var ok) && ok.ValueKind == JsonValueKind.False)
{
var message = root.TryGetProperty("message", out var m) ? m.GetString() : "maps 列表失败";
throw new InvalidOperationException(message ?? "maps 列表失败");
}
JsonElement data = root;
if (root.TryGetProperty("data", out var d) && d.ValueKind == JsonValueKind.Object)
data = d;
if (data.TryGetProperty("directory", out var dir) && dir.ValueKind == JsonValueKind.String)
return dir.GetString();
return null;
}
}