using AmtScanner.Api.Configuration; using AmtScanner.Api.Data; using AmtScanner.Api.Middleware; using AmtScanner.Api.Services; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; using Microsoft.IdentityModel.Tokens; using System.Text; var builder = WebApplication.CreateBuilder(args); // 监听所有 IP 地址,允许外部访问 builder.WebHost.UseUrls("http://0.0.0.0:5000"); // Add services to the container builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); // Add CORS builder.Services.AddCors(options => { options.AddPolicy("AllowFrontend", policy => { policy.WithOrigins("http://localhost:5173", "http://localhost:3000", "http://localhost:3001", "http://localhost:3006", "http://localhost:3007") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); // Add Database var databaseProvider = builder.Configuration.GetValue("DatabaseProvider", "SQLite"); if (databaseProvider == "MySQL") { var connectionString = builder.Configuration.GetConnectionString("MySqlConnection"); builder.Services.AddDbContext(options => options.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString))); } else { builder.Services.AddDbContext(options => options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"))); } // Add JWT Configuration builder.Services.Configure(builder.Configuration.GetSection(JwtSettings.SectionName)); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Add AMT Services builder.Services.AddSingleton(); builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); // Add Screen Stream Proxy Service builder.Services.AddSingleton(); // Add Guacamole Service builder.Services.AddHttpClient("Guacamole"); builder.Services.AddSingleton(); // Add JWT Authentication var jwtSettings = builder.Configuration.GetSection(JwtSettings.SectionName).Get()!; builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = jwtSettings.Issuer, ValidAudience = jwtSettings.Audience, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey)), ClockSkew = TimeSpan.Zero }; options.Events = new JwtBearerEvents { OnAuthenticationFailed = context => { if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)) { context.Response.Headers.Append("Token-Expired", "true"); } return Task.CompletedTask; } }; }); var app = builder.Build(); // Configure the HTTP request pipeline if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseCors("AllowFrontend"); // Add WebSocket support app.UseWebSockets(new WebSocketOptions { KeepAliveInterval = TimeSpan.FromSeconds(30) }); // Add global exception handler app.UseGlobalExceptionHandler(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); // Ensure database is created using (var scope = app.Services.CreateScope()) { var db = scope.ServiceProvider.GetRequiredService(); try { // Apply migrations try { db.Database.Migrate(); } catch (Exception migrationEx) when (migrationEx.Message.Contains("already exists")) { Console.WriteLine("⚠️ 表已存在,尝试标记迁移为已完成..."); var pendingMigrations = db.Database.GetPendingMigrations().ToList(); foreach (var migration in pendingMigrations) { try { db.Database.ExecuteSqlRaw( "INSERT IGNORE INTO `__EFMigrationsHistory` (`MigrationId`, `ProductVersion`) VALUES ({0}, {1})", migration, "8.0.0"); Console.WriteLine($"✅ 已标记迁移: {migration}"); } catch { } } } Console.WriteLine($"✅ 数据库连接成功: {databaseProvider}"); // 确保 AgentDevices_new 表存在 try { db.Database.ExecuteSqlRaw(@" CREATE TABLE IF NOT EXISTS `AgentDevices_new` ( `Uuid` VARCHAR(36) NOT NULL PRIMARY KEY, `Hostname` VARCHAR(100) DEFAULT '', `IpAddress` VARCHAR(45) DEFAULT '', `MacAddress` VARCHAR(17) DEFAULT '', `SubnetMask` VARCHAR(15) DEFAULT '', `Gateway` VARCHAR(45) DEFAULT '', `OsName` VARCHAR(200) DEFAULT '', `OsVersion` VARCHAR(100) DEFAULT '', `OsArchitecture` VARCHAR(20) DEFAULT '', `CpuName` VARCHAR(200) DEFAULT '', `TotalMemoryMB` BIGINT DEFAULT 0, `Manufacturer` VARCHAR(100) DEFAULT '', `Model` VARCHAR(100) DEFAULT '', `SerialNumber` VARCHAR(100) DEFAULT '', `CurrentUser` VARCHAR(100) DEFAULT '', `UserDomain` VARCHAR(100) DEFAULT '', `BootTime` DATETIME NULL, `LastReportAt` DATETIME NULL, `IsOnline` TINYINT(1) DEFAULT 0, `CreatedAt` DATETIME NOT NULL, INDEX `IX_AgentDevices_new_IpAddress` (`IpAddress`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; "); Console.WriteLine("✅ AgentDevices_new 表已就绪"); } catch (Exception ex) { Console.WriteLine($"⚠️ 创建 AgentDevices_new 表: {ex.Message}"); } // 初始化种子数据 await DbSeeder.SeedAsync(db); } catch (Exception ex) { Console.WriteLine($"❌ 数据库初始化失败: {ex.Message}"); throw; } } app.Run();