fix(server): 转发头可信代理可配置、登录冷启动非阻塞与启动路径/授权健壮化
Program.cs 的 ForwardedHeaders 改为读 ForwardedHeaders:KnownProxies 显式收紧可信代理 (未配置则维持信任所有,适合同机/内网;配置后按数量收紧 ForwardLimit,解析全失败 fail-closed), 并补 AnyAuthed 授权策略、内容根/前端目录三级探测、OpsAuditStore 与 HttpClientFactory 注册; AuthController 登录改 MaybeStart(waitForReady:false) 避免 SimpleLite 冷启动阻塞登录; SimpleLiteLauncher 增强相对 ContentRoot 的文件/目录解析,兼容从 bin 目录运行。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -61,7 +61,7 @@ public sealed class SimpleLiteLauncher : IDisposable
|
||||
/// </summary>
|
||||
/// <param name="launchMode">"WebOnly" 或 "DesktopAndWeb"(大小写不敏感)。</param>
|
||||
/// <returns>本次调用产生的状态摘要,可写入登录响应或日志。</returns>
|
||||
public LaunchResult MaybeStart(string launchMode)
|
||||
public LaunchResult MaybeStart(string launchMode, bool waitForReady = true)
|
||||
{
|
||||
var displayMode = NormalizeDisplayMode(launchMode);
|
||||
|
||||
@@ -150,7 +150,7 @@ public sealed class SimpleLiteLauncher : IDisposable
|
||||
|
||||
var workdir = string.IsNullOrWhiteSpace(_opts.WorkingDirectory)
|
||||
? Path.GetDirectoryName(resolved) ?? Environment.CurrentDirectory
|
||||
: Path.GetFullPath(_opts.WorkingDirectory);
|
||||
: ResolveConfiguredDirectory(_opts.WorkingDirectory) ?? Path.GetDirectoryName(resolved) ?? Environment.CurrentDirectory;
|
||||
|
||||
var arguments = BuildArguments(displayMode, _opts.Arguments);
|
||||
|
||||
@@ -182,6 +182,17 @@ public sealed class SimpleLiteLauncher : IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
// M1:登录路径传 waitForReady=false —— 进程拉起后立即返回,不再同步阻塞最长
|
||||
// ReadinessTimeoutMs 等端口就绪(避免冷启动登录干等十几秒)。前端可轮询
|
||||
// GET /api/health/simplelite 获知就绪状态。
|
||||
if (!waitForReady)
|
||||
{
|
||||
return new LaunchResult(true, "Starting",
|
||||
$"projection :{_opts.ProjectionPort} readiness wait skipped (async), displayMode={displayMode}",
|
||||
DisplayMode: displayMode,
|
||||
Warning: null);
|
||||
}
|
||||
|
||||
var ready = WaitForProjectionReady();
|
||||
return new LaunchResult(true, ready ? "Ready" : "StartedButNotReady",
|
||||
ready ? $"projection :{_opts.ProjectionPort} reachable, displayMode={displayMode}"
|
||||
@@ -262,7 +273,7 @@ public sealed class SimpleLiteLauncher : IDisposable
|
||||
public string? ResolveWorkingDirectory()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_opts.WorkingDirectory))
|
||||
return Path.GetFullPath(_opts.WorkingDirectory);
|
||||
return ResolveConfiguredDirectory(_opts.WorkingDirectory);
|
||||
var resolved = ResolveExecutable(_opts.ExecutablePath);
|
||||
return resolved == null ? null : (Path.GetDirectoryName(resolved) ?? Environment.CurrentDirectory);
|
||||
}
|
||||
@@ -518,8 +529,8 @@ public sealed class SimpleLiteLauncher : IDisposable
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(configured))
|
||||
{
|
||||
var p = Path.IsPathRooted(configured) ? configured : Path.GetFullPath(configured, _env.ContentRootPath);
|
||||
return File.Exists(p) ? p : null;
|
||||
var p = ResolveConfiguredFile(configured);
|
||||
if (p != null) return p;
|
||||
}
|
||||
|
||||
var cwd = _env.ContentRootPath;
|
||||
@@ -562,6 +573,42 @@ public sealed class SimpleLiteLauncher : IDisposable
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? ResolveConfiguredFile(string configured)
|
||||
{
|
||||
foreach (var baseDir in EnumeratePathBases())
|
||||
{
|
||||
var p = Path.IsPathRooted(configured)
|
||||
? configured
|
||||
: Path.GetFullPath(configured, baseDir);
|
||||
if (File.Exists(p)) return p;
|
||||
if (Path.IsPathRooted(configured)) break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private string? ResolveConfiguredDirectory(string configured)
|
||||
{
|
||||
foreach (var baseDir in EnumeratePathBases())
|
||||
{
|
||||
var p = Path.IsPathRooted(configured)
|
||||
? configured
|
||||
: Path.GetFullPath(configured, baseDir);
|
||||
if (Directory.Exists(p)) return p;
|
||||
if (Path.IsPathRooted(configured)) break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private IEnumerable<string> EnumeratePathBases()
|
||||
{
|
||||
var dir = new DirectoryInfo(_env.ContentRootPath);
|
||||
while (dir != null)
|
||||
{
|
||||
yield return dir.FullName;
|
||||
dir = dir.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
private bool WaitForProjectionReady()
|
||||
{
|
||||
if (_opts.ReadinessTimeoutMs == 0) return false;
|
||||
|
||||
Reference in New Issue
Block a user