using BoardApp.Config;
|
using BoardApp.Middleware;
|
using BoardApp.Services;
|
using Microsoft.AspNetCore.Authentication.Negotiate;
|
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.Server.IISIntegration;
|
|
var builder = WebApplication.CreateBuilder(args);
|
|
// Load app.config.json early so we can configure session cookie flags.
|
var earlyCfgLoader = new BoardConfigLoader();
|
var appCfg = earlyCfgLoader.LoadAppConfig();
|
|
builder.Services.AddControllersWithViews();
|
builder.Services.AddHttpContextAccessor();
|
|
builder.Services.AddSingleton<BoardConfigLoader>();
|
builder.Services.AddSingleton<ScenarioService>();
|
builder.Services.AddSingleton<UserScenarioService>();
|
builder.Services.AddSingleton<SqlDataSourceService>();
|
builder.Services.AddSingleton<WarehouseCalendarService>();
|
builder.Services.AddSingleton<LdapAuthService>();
|
builder.Services.AddSingleton<AdAuthenticationService>();
|
|
var isIisHost = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH"));
|
if (isIisHost)
|
{
|
builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme);
|
}
|
else
|
{
|
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
|
}
|
|
static SameSiteMode ParseSameSite(object? v)
|
{
|
var s = (v as string)?.Trim().ToLowerInvariant();
|
return s switch
|
{
|
"strict" => SameSiteMode.Strict,
|
"none" => SameSiteMode.None,
|
_ => SameSiteMode.Lax
|
};
|
}
|
|
// Session cookie must match Node version for behavior parity.
|
builder.Services.AddDistributedMemoryCache();
|
builder.Services.AddSession(options =>
|
{
|
options.Cookie.Name = "board.sid";
|
options.Cookie.Path = "/";
|
options.Cookie.HttpOnly = true;
|
options.Cookie.IsEssential = true;
|
options.Cookie.SecurePolicy = appCfg.CookieSecure
|
? CookieSecurePolicy.Always
|
: CookieSecurePolicy.SameAsRequest;
|
options.Cookie.SameSite = ParseSameSite(appCfg.CookieSameSite);
|
options.Cookie.MaxAge = TimeSpan.FromMilliseconds(appCfg.SessionMaxAgeMs);
|
options.IdleTimeout = TimeSpan.FromMilliseconds(appCfg.SessionMaxAgeMs);
|
});
|
|
var app = builder.Build();
|
|
if (appCfg.TrustProxy)
|
{
|
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
{
|
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
});
|
}
|
|
// Keep external URL shape: http://host:3000/board/...
|
var pathBase = Environment.GetEnvironmentVariable("BOARD_PATH_BASE");
|
if (string.IsNullOrWhiteSpace(pathBase))
|
{
|
pathBase = "/board";
|
}
|
if (!pathBase.StartsWith("/"))
|
{
|
pathBase = "/" + pathBase;
|
}
|
app.UsePathBase(pathBase);
|
|
app.Use(async (ctx, next) =>
|
{
|
ctx.Items["BoardAppConfig"] = appCfg;
|
await next();
|
});
|
|
// /board/static/x → wwwroot/static/x(勿设 RequestPath=/static,否则会映射到 wwwroot/x 导致 404)
|
app.UseStaticFiles();
|
|
app.UseRouting();
|
app.UseSession();
|
app.UseAuthentication();
|
|
app.UseMiddleware<BoardRequireAuthMiddleware>();
|
|
app.MapControllerRoute(
|
name: "default",
|
pattern: "{controller=Board}/{action=Home}/{id?}");
|
|
// IIS(含进程内托管)或容器常由宿主注入监听地址,勿再硬编码 Kestrel URL。
|
var urlsFromEnv = Environment.GetEnvironmentVariable("ASPNETCORE_URLS");
|
var iisPhysicalPath = Environment.GetEnvironmentVariable("ASPNETCORE_IIS_PHYSICAL_PATH");
|
if (!string.IsNullOrWhiteSpace(urlsFromEnv) || !string.IsNullOrWhiteSpace(iisPhysicalPath))
|
{
|
app.Run();
|
}
|
else
|
{
|
app.Run($"http://0.0.0.0:{appCfg.Port}");
|
}
|
|