admin/src/SimpleAdmin.Api/SimpleAdminApiModule.cs
2026-10-10 16:41:28 +08:00

221 lines
8.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Fake.AspNetCore;
using Fake.Autofac;
using Fake.Modularity;
using Fake.Rbac.Application;
using Fake.Rbac.Infrastructure;
using Fake.AspNetCore.Auditing;
using Fake.AspNetCore.ExceptionHandling;
using Fake.AspNetCore.Newtonsoft;
using Fake.AspNetCore.Swagger;
using Fake.EventBus.IntegrationEventLog;
using Fake.FeiShu;
using Fake.FileManagement.Application;
using Fake.FileManagement.Infrastructure;
using Fake.ObjectStorage;
using Fake.Security.Claims;
using Fake.Serilog;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Oms.Application;
using Oms.SqlSugarCore;
using SimpleAdmin.Api.Auth;
using SimpleAdmin.Api.Storage;
using SimpleAdmin.Api.Swagger;
using SimpleAdmin.Api.WeChat;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace SimpleAdmin.Api;
[DependsOn(
typeof(FakeAutofacModule),
typeof(OmsApplicationModule),
typeof(OmsSqlSugarCoreModule),
typeof(FakeRbacApplicationModule),
typeof(FakeRbacInfrastructureModule),
typeof(FakeFileManagementApplicationModule),
typeof(FakeFileManagementInfrastructureModule),
typeof(FakeObjectStorageTencentCosModule),
// 在 RabbitMQ 物理总线之后 Replace IDistributedEventBus → Outbox
typeof(FakeEventBusIntegrationEventLogModule),
typeof(FakeAspNetCoreModule),
typeof(FakeSerilogModule)
)]
public class SimpleAdminApiModule : FakeModule
{
private const string DefaultCorsPolicyName = "default";
public override void PreConfigureServices(ServiceConfigurationContext context)
{
FakeClaimTypes.UserId = "mapId";
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
var services = context.Services;
var configuration = context.Services.GetConfiguration();
// 配置动态 API - 扫描 OMS / RBAC / FileManagement 应用服务
services.Configure<FakeAspNetCoreMvcOptions>(options =>
{
options.ApplicationServices2Controller<OmsApplicationModule>();
options.ApplicationServices2Controller<SimpleAdminApiModule>(settings =>
{
settings.RootPath = "rbac";
settings.TypePredicate = type =>
type == typeof(AuthService) || type == typeof(WeChatCustomerService);
});
options.ApplicationServices2Controller<FakeRbacApplicationModule>(settings =>
{
settings.RootPath = "rbac";
settings.TypePredicate = type =>
type != typeof(Fake.Rbac.Application.Services.AuthService) &&
type != typeof(Fake.Rbac.Application.Services.UserService);
});
options.ApplicationServices2Controller<FakeFileManagementApplicationModule>(settings =>
{
settings.RootPath = "files";
});
});
services.AddOmsWeChat(configuration);
services.AddSingleton<IRbacAuthCache, RbacAuthCache>();
// Outbox / Inbox 与业务同库(EF),通过 DbTransaction 征用 SqlSugar 事务
services.AddDbContext<IntegrationEventLogContext>(options =>
{
var connectionString = configuration.GetConnectionString("IntegrationEventLog")
?? configuration.GetConnectionString("Default")
?? configuration["ConnectionStrings:Default"]
?? string.Empty;
var serverVersion = ServerVersion.AutoDetect(connectionString);
options.UseMySql(connectionString, serverVersion);
#if DEBUG
options.EnableSensitiveDataLogging();
#endif
});
//Json格式化全局处理
context.Services.AddFakeNewtonsoft();
services.AddFakeAspNetCoreAuditing();
// 添加 Fake Swagger 支持
services.AddFakeSwaggerGen(addSecurity: true);
// Fake.Rbac 菜单/组织/权限/角色接口无 XML 注释,补全 summary
services.Configure<SwaggerGenOptions>(options =>
{
options.OperationFilter<RbacSwaggerOperationFilter>();
});
services.AddCors(options =>
{
options.AddPolicy(DefaultCorsPolicyName, builder =>
{
builder.WithOrigins(configuration.GetSection("App:CorsOrigins").Get<string[]>() ?? [])
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
services.Configure<ForwardedHeadersOptions>(options =>
{
// 反向代理场景下恢复客户端真实来源信息,供 Swagger、鉴权和重定向等中间件使用
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
ForwardedHeaders.XForwardedProto |
ForwardedHeaders.XForwardedHost;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
services.AddFeiShuExceptionSubscriber();
// 草稿已落库失败:结构化 Details + 清理 msg 机器标记
services.AddTransient<DefaultException2ResponseConverter>();
var exceptionConverterDescriptors = services
.Where(d => d.ServiceType == typeof(IException2ResponseConverter))
.ToList();
foreach (var descriptor in exceptionConverterDescriptors)
{
services.Remove(descriptor);
}
services.AddTransient<IException2ResponseConverter>(sp =>
new ExceptionHandling.OmsException2ResponseConverter(
sp.GetRequiredService<DefaultException2ResponseConverter>()));
// 全局授权配置:所有接口默认需要授权
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
// 添加授权服务
services.AddAuthorization();
services.AddHostedService<ObjectStorageStartupLogger>();
}
public override void ConfigureApplication(ApplicationConfigureContext context)
{
var app = context.GetWebApplication();
// 必须在读取 Scheme/Host/PathBase 的中间件之前执行,否则 Swagger 会生成错误的请求地址
app.UseForwardedHeaders();
// 虚拟路由-网关适配
app.UsePathBase(app.Configuration["ASPNETCORE_PATHBASE"]);
// Swagger
app.UseFakeSwagger();
// 异常处理
app.UseFakeExceptionHandling();
// CORS
app.UseCors(DefaultCorsPolicyName);
// 静态文件服务(用于头像等上传文件)
app.UseStaticFiles();
// 路由 - 必须在认证和授权之前
app.UseRouting();
// OpenAPI 验签需读取原始 Body,允许二次读流
app.Use(async (ctx, next) =>
{
if (ctx.Request.Path.StartsWithSegments("/openapi"))
{
ctx.Request.EnableBuffering();
}
await next();
});
// 认证和授权
app.UseAuthentication();
app.UseAuthorization();
// 角色/菜单写操作后失效登录用户信息缓存
app.UseMiddleware<RbacCacheInvalidationMiddleware>();
// 端点映射
app.MapControllers();
// FileManagement / Outbox 与业务同库并行(EF)
using (var scope = app.Services.CreateScope())
{
var fileDb = scope.ServiceProvider.GetRequiredService<FileManagementDbContext>();
fileDb.Database.Migrate();
var outboxDb = scope.ServiceProvider.GetRequiredService<IntegrationEventLogContext>();
IntegrationEventLogSchema.EnsureTablesAsync(outboxDb).GetAwaiter().GetResult();
}
app.Services.GetRequiredService<IFeiShuNotificationService>().Send("Application started");
}
}