using FreeSql; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.Authorization; using Microsoft.IdentityModel.Tokens; using Scalar.AspNetCore; using Serilog; using Service.AppSettingModel; using WebApi; using WebApi.Middleware; using Yitter.IdGenerator; // 初始化雪花算法ID生成器 var options = new IdGeneratorOptions(1); // WorkerId 为 1,可根据实际部署情况调整 YitIdHelper.SetIdGenerator(options); var builder = WebApplication.CreateBuilder(args); // 配置 Serilog builder.Host.UseSerilog((context, loggerConfig) => { loggerConfig.ReadFrom.Configuration(context.Configuration); }); // Add services to the container. builder.Services.AddControllers(mvcOptions => { var policy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme) .RequireAuthenticatedUser() .Build(); mvcOptions.Filters.Add(new AuthorizeFilter(policy)); }); builder.Services.AddOpenApi(); builder.Services.AddHttpClient(); // 配置 CORS builder.Services.AddCors(corsOptions => { corsOptions.AddDefaultPolicy(policy => { policy.WithOrigins("http://localhost:5173") .AllowAnyHeader() .AllowAnyMethod(); }); }); // 绑定配置 builder.Services.Configure(builder.Configuration.GetSection("EmailSettings")); builder.Services.Configure(builder.Configuration.GetSection("OpenAI")); builder.Services.Configure(builder.Configuration.GetSection("JwtSettings")); builder.Services.Configure(builder.Configuration.GetSection("AuthSettings")); // 配置JWT认证 var jwtSettings = builder.Configuration.GetSection("JwtSettings"); var secretKey = jwtSettings["SecretKey"]!; var key = Encoding.UTF8.GetBytes(secretKey); builder.Services.AddAuthentication(authenticationOptions => { authenticationOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; authenticationOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(jwtBearerOptions => { jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = jwtSettings["Issuer"], ValidAudience = jwtSettings["Audience"], IssuerSigningKey = new SymmetricSecurityKey(key), ClockSkew = TimeSpan.Zero }; jwtBearerOptions.Events = new JwtBearerEvents { OnChallenge = async context => { context.Response.StatusCode = StatusCodes.Status401Unauthorized; context.Response.ContentType = "application/json"; await context.Response.WriteAsJsonAsync(BaseResponse.Fail("未登录")); }, OnForbidden = async context => { context.Response.StatusCode = StatusCodes.Status403Forbidden; context.Response.ContentType = "application/json"; await context.Response.WriteAsJsonAsync(BaseResponse.Fail("权限不足")); } }; }); builder.Services.AddAuthorization(); // 配置 FreeSql + SQLite var dbPath = Path.Combine(AppContext.BaseDirectory, "database"); if (!Directory.Exists(dbPath)) { Directory.CreateDirectory(dbPath); } // 使用绝对路径作为数据库文件路径 var dbFilePath = Path.Combine(dbPath, "EmailBill.db"); var connectionString = $"Data Source={dbFilePath}"; Log.Information("数据库路径: {DbPath}", dbFilePath); var fsql = new FreeSqlBuilder() .UseConnectionString(DataType.Sqlite, connectionString) .UseAutoSyncStructure(true) .UseLazyLoading(true) .UseMonitorCommand( cmd => { Log.Verbose("执行SQL: {Sql}", cmd.CommandText); } ) .Build(); fsql.UseJsonMap(); builder.Services.AddSingleton(fsql); // 自动扫描注册服务和仓储 builder.Services.AddServices(); // 配置 Quartz.NET 定时任务 builder.AddScheduler(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.MapOpenApi(); app.MapScalarApiReference(); } // 启用静态文件服务 app.UseDefaultFiles(); app.UseStaticFiles(); // 启用 CORS app.UseCors(); // 启用请求ID跟踪 app.UseRequestId(); // 启用认证和授权 app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); // 添加 SPA 回退路由(用于前端路由) app.MapFallbackToFile("index.html"); app.Run();