using IM_API.Configs; using IM_API.Configs.Options; using IM_API.Filters; using IM_API.Hubs; using IM_API.Models; using IM_API.Tools; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.FileProviders; using Microsoft.IdentityModel.Tokens; using StackExchange.Redis; using System.Text; using System.Text.Json; using System.Text.Json.Serialization; namespace IM_API { public class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. IConfiguration configuration = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .Build(); var conOptions = configuration.GetSection("ConnectionStrings").Get(); //注入数据库上下文 builder.Services.AddDbContext(options => { options.UseMySql(conOptions.DefaultConnection,ServerVersion.AutoDetect(conOptions.DefaultConnection)); }); //注入redis var redis = ConnectionMultiplexer.Connect(conOptions.Redis); builder.Services.AddSingleton(redis); builder.Services.AddStackExchangeRedisCache(options => { options.ConnectionMultiplexerFactory = () => Task.FromResult(redis); }); builder.Services.AddRabbitMQ(configuration.GetSection("RabbitMqOptions").Get()); builder.Services.AddHttpContextAccessor(); builder.Services.AddAllService(configuration); builder.Services.AddSignalR().AddJsonProtocol(options => { // 枚举输出字符串 options.PayloadSerializerOptions.Converters.Add(new JsonStringEnumConverter()); options.PayloadSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; }); //允许所有来源(跨域) builder.Services.AddCors(options => { options.AddDefaultPolicy(policy => { policy.AllowAnyHeader() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials() .SetIsOriginAllowed(origin => { // 允许所有来自本地或特定网段的请求 var host = new Uri(origin).Host; return host == "localhost" || host.StartsWith("192.168."); }); }); }); //凭证处理 builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { //https非必须 options.RequireHttpsMetadata = false; //保存token options.SaveToken = true; options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters { //验证签发者 ValidateIssuer = true, ValidIssuer = configuration["Jwt:Issuer"], //验证受众 ValidateAudience = true, ValidAudience = configuration["Jwt:Audience"], //验证签名密钥 ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"])), //时间偏差容忍 ValidateLifetime = true, ClockSkew = TimeSpan.FromSeconds(30) }; //websocket token凭证处理 options.Events = new JwtBearerEvents { OnMessageReceived = context => { var accessToken = context.Request.Query["access_token"]; if (!string.IsNullOrEmpty(accessToken)) { context.Token = accessToken; } return Task.CompletedTask; }, OnAuthenticationFailed = context => { Console.WriteLine("Authentication failed: " + context.Exception.Message); return Task.CompletedTask; } }; }); builder.Services.AddControllers(options => { options.Filters.Add(); }).AddJsonOptions(options => { // 保持 ISO 8601 格式 //options.JsonSerializerOptions.Converters.Add(new UtcDateTimeConverter()); // 将枚举转换为字符串 options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); // 建议:保持驼峰命名 options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; }); builder.Services.AddModelValidation(configuration); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); string uploadPath = Path.Combine(Directory.GetCurrentDirectory(), "uploads","files"); // 2. 如果文件夹不存在则创建,防止程序启动报错 if (!Directory.Exists(uploadPath)) { Directory.CreateDirectory(uploadPath); } // 3. 配置静态文件映射 app.UseStaticFiles(new StaticFileOptions { // 指定物理磁盘路径 FileProvider = new PhysicalFileProvider(uploadPath), // 指定浏览器访问的虚拟前缀(例如:http://localhost:5000/files/1.jpg) RequestPath = "/uploads/files" }); app.UseCors(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.MapHub("/chat").RequireCors(); app.Run(); } } }