调整 .gitignore 以适配 backends 目录结构

将 MiGu.Server 相关忽略规则迁移至 backends/MiGu.Server,并新增对 .tmp-build* 和 /.cursor/rules 的忽略,优化敏感数据与临时文件的管理。
This commit is contained in:
ArtoriasWu
2026-06-22 08:55:55 +08:00
parent 45f0261ed7
commit 87629a8537
46 changed files with 10 additions and 3 deletions
@@ -0,0 +1,82 @@
using System.Security.Cryptography;
namespace MiGu.Server.Auth;
/// <summary>
/// MiGu.Server ↔ SimpleLite 8222 之间的 **内部共享 token**。
///
/// 设计动机:SimpleLite 8222 的 EmbedIO WebApiReflectionApi / PersistenceApi / MapEditApi
/// 历史上完全无鉴权,远程访问 = 接管调度内核。为不在 SimpleLite 侧实现完整 JWT 验签
/// (减少 SimpleLite 复杂度),采用一个轻量约定:
///
/// - <b>本机回环</b>127.0.0.1 / ::1SimpleLite 直接放行(开发机直连不受影响);
/// - <b>其它来源</b>必须携带 <c>X-Platform-Internal-Token</c> header
/// - MiGu.Server YARP 反代 <c>/api/sl/*</c> 到 SimpleLite 8222 时,YARP transform
/// 会自动追加该 header
/// - SimpleLite 端通过 <c>simple.json:platform.internalToken</c> 或环境变量
/// <c>SIMPLELITE__PLATFORM__INTERNALTOKEN</c> 配置同一个 token;两端不一致即拒绝。
///
/// Token 来源优先级:
/// 1) appsettings.json:Internal:Token 显式配置(生产推荐:strong, length ≥ 32
/// 2) 环境变量 PLATFORM__INTERNAL__TOKEN
/// 3) 兜底:进程随机 64 字节 base64,并在日志告警 + 写入 <c>data/.internal-token</c>
/// 文件供本机 SimpleLite 读取(同机部署常见场景)
/// </summary>
public sealed class InternalTokenStore
{
public string Token { get; }
public bool IsEphemeral { get; }
public string? PersistedFilePath { get; }
public InternalTokenStore(IConfiguration config, IWebHostEnvironment env, ILogger<InternalTokenStore> logger)
{
var configured = config["Internal:Token"];
if (!string.IsNullOrWhiteSpace(configured) && configured != "REPLACE_ME")
{
Token = configured;
IsEphemeral = false;
logger.LogInformation("Internal token 从配置读取(长度 {Len})。", Token.Length);
return;
}
// 兜底:进程随机 + 落地到 data/.internal-token 便于同机 SimpleLite 读取
var dataDir = Path.Combine(env.ContentRootPath, "data");
Directory.CreateDirectory(dataDir);
var file = Path.Combine(dataDir, ".internal-token");
if (File.Exists(file))
{
try
{
var existing = File.ReadAllText(file).Trim();
if (existing.Length >= 32)
{
Token = existing;
IsEphemeral = false;
PersistedFilePath = file;
logger.LogInformation("Internal token 复用 {File}(长度 {Len})。", file, Token.Length);
return;
}
}
catch (Exception ex)
{
logger.LogWarning(ex, "读取 {File} 失败,将重新生成 internal token。", file);
}
}
Token = Convert.ToBase64String(RandomNumberGenerator.GetBytes(48));
IsEphemeral = true;
try
{
File.WriteAllText(file, Token);
PersistedFilePath = file;
logger.LogWarning(
"Internal token 未配置 —— 已生成进程随机值并写入 {File}(重启后保留)。" +
"若 MiGu.Server 与 SimpleLite 不在同一台机器,请把同一个值写入 SimpleLite 端 simple.json:platform.internalToken。",
file);
}
catch (Exception ex)
{
logger.LogError(ex, "internal token 落盘失败 —— 远程 SimpleLite 调用将无法通过鉴权(每次重启 token 都不同)。");
}
}
}