diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/LINGYUN.MicroService.Internal.ApiGateway.sln b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/LINGYUN.MicroService.Internal.ApiGateway.sln index 4c3da473a..df6917a3b 100644 --- a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/LINGYUN.MicroService.Internal.ApiGateway.sln +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/LINGYUN.MicroService.Internal.ApiGateway.sln @@ -54,6 +54,24 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Logging.Serilog EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Logging", "..\..\..\aspnet-core\framework\logging\LINGYUN.Abp.Logging\LINGYUN.Abp.Logging.csproj", "{745E278B-AEDC-49CE-872E-FAEB6BF195B1}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "open-api", "open-api", "{BA1D1A21-61AD-4674-A5FB-AE4FF61E9CC1}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenApi", "..\..\..\aspnet-core\framework\open-api\LINGYUN.Abp.OpenApi\LINGYUN.Abp.OpenApi.csproj", "{F4B22A53-9483-4906-86F9-2A23E6D46CE9}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.OpenApi.Authorization", "..\..\..\aspnet-core\framework\open-api\LINGYUN.Abp.OpenApi.Authorization\LINGYUN.Abp.OpenApi.Authorization.csproj", "{7F3CC521-FE9B-4E52-BF52-93C41E2F34ED}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.MicroService.OpenApi.Gateway", "src\LINGYUN.MicroService.OpenApi.Gateway\LINGYUN.MicroService.OpenApi.Gateway.csproj", "{433D2E8C-E15A-47BC-AB49-25307C05E849}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "identity", "identity", "{667EE009-DA55-4F87-9A07-F9DE76AF6EBF}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Identity.Session", "..\..\..\aspnet-core\modules\identity\LINGYUN.Abp.Identity.Session\LINGYUN.Abp.Identity.Session.csproj", "{F6CA275D-5843-4349-851C-B56A3A74F545}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Identity.Session.AspNetCore", "..\..\..\aspnet-core\modules\identity\LINGYUN.Abp.Identity.Session.AspNetCore\LINGYUN.Abp.Identity.Session.AspNetCore.csproj", "{80965673-2598-44E6-98C7-CCF8F0D4A4A0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.IP2Region", "..\..\..\aspnet-core\framework\common\LINGYUN.Abp.IP2Region\LINGYUN.Abp.IP2Region.csproj", "{85CAA0EF-883D-469B-BBEC-735758A3FC9B}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OpenApi.Sdk", "..\..\..\aspnet-core\framework\open-api\OpenApi.Sdk\OpenApi.Sdk.csproj", "{551D8B82-B619-4846-BC3B-E883BA312D9A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -116,6 +134,34 @@ Global {745E278B-AEDC-49CE-872E-FAEB6BF195B1}.Debug|Any CPU.Build.0 = Debug|Any CPU {745E278B-AEDC-49CE-872E-FAEB6BF195B1}.Release|Any CPU.ActiveCfg = Release|Any CPU {745E278B-AEDC-49CE-872E-FAEB6BF195B1}.Release|Any CPU.Build.0 = Release|Any CPU + {F4B22A53-9483-4906-86F9-2A23E6D46CE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F4B22A53-9483-4906-86F9-2A23E6D46CE9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F4B22A53-9483-4906-86F9-2A23E6D46CE9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F4B22A53-9483-4906-86F9-2A23E6D46CE9}.Release|Any CPU.Build.0 = Release|Any CPU + {7F3CC521-FE9B-4E52-BF52-93C41E2F34ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7F3CC521-FE9B-4E52-BF52-93C41E2F34ED}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7F3CC521-FE9B-4E52-BF52-93C41E2F34ED}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7F3CC521-FE9B-4E52-BF52-93C41E2F34ED}.Release|Any CPU.Build.0 = Release|Any CPU + {433D2E8C-E15A-47BC-AB49-25307C05E849}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {433D2E8C-E15A-47BC-AB49-25307C05E849}.Debug|Any CPU.Build.0 = Debug|Any CPU + {433D2E8C-E15A-47BC-AB49-25307C05E849}.Release|Any CPU.ActiveCfg = Release|Any CPU + {433D2E8C-E15A-47BC-AB49-25307C05E849}.Release|Any CPU.Build.0 = Release|Any CPU + {F6CA275D-5843-4349-851C-B56A3A74F545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F6CA275D-5843-4349-851C-B56A3A74F545}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F6CA275D-5843-4349-851C-B56A3A74F545}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F6CA275D-5843-4349-851C-B56A3A74F545}.Release|Any CPU.Build.0 = Release|Any CPU + {80965673-2598-44E6-98C7-CCF8F0D4A4A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {80965673-2598-44E6-98C7-CCF8F0D4A4A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {80965673-2598-44E6-98C7-CCF8F0D4A4A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {80965673-2598-44E6-98C7-CCF8F0D4A4A0}.Release|Any CPU.Build.0 = Release|Any CPU + {85CAA0EF-883D-469B-BBEC-735758A3FC9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {85CAA0EF-883D-469B-BBEC-735758A3FC9B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {85CAA0EF-883D-469B-BBEC-735758A3FC9B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {85CAA0EF-883D-469B-BBEC-735758A3FC9B}.Release|Any CPU.Build.0 = Release|Any CPU + {551D8B82-B619-4846-BC3B-E883BA312D9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {551D8B82-B619-4846-BC3B-E883BA312D9A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {551D8B82-B619-4846-BC3B-E883BA312D9A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {551D8B82-B619-4846-BC3B-E883BA312D9A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -140,6 +186,15 @@ Global {3F3CA517-8A22-4B85-A2E8-3BB90B99A158} = {EE01F3C2-14D1-4089-8C02-00C8083D9795} {4AF54F2B-D650-4B4D-AD05-2AA882DD2A49} = {3B460BD3-26EE-4BAC-A8B8-CFDF5F108A63} {745E278B-AEDC-49CE-872E-FAEB6BF195B1} = {3B460BD3-26EE-4BAC-A8B8-CFDF5F108A63} + {BA1D1A21-61AD-4674-A5FB-AE4FF61E9CC1} = {80E45092-1181-456D-B88C-7DDCB7F16368} + {F4B22A53-9483-4906-86F9-2A23E6D46CE9} = {BA1D1A21-61AD-4674-A5FB-AE4FF61E9CC1} + {7F3CC521-FE9B-4E52-BF52-93C41E2F34ED} = {BA1D1A21-61AD-4674-A5FB-AE4FF61E9CC1} + {433D2E8C-E15A-47BC-AB49-25307C05E849} = {E8067AED-2B6E-4134-AAF8-9101457D709A} + {667EE009-DA55-4F87-9A07-F9DE76AF6EBF} = {80E45092-1181-456D-B88C-7DDCB7F16368} + {F6CA275D-5843-4349-851C-B56A3A74F545} = {667EE009-DA55-4F87-9A07-F9DE76AF6EBF} + {80965673-2598-44E6-98C7-CCF8F0D4A4A0} = {667EE009-DA55-4F87-9A07-F9DE76AF6EBF} + {85CAA0EF-883D-469B-BBEC-735758A3FC9B} = {EE01F3C2-14D1-4089-8C02-00C8083D9795} + {551D8B82-B619-4846-BC3B-E883BA312D9A} = {BA1D1A21-61AD-4674-A5FB-AE4FF61E9CC1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {972464AB-1B23-4D87-89A2-13271E1873B9} diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/AbpHostingHostBuilderExtensions.cs b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/AbpHostingHostBuilderExtensions.cs new file mode 100644 index 000000000..ed6a1adf8 --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/AbpHostingHostBuilderExtensions.cs @@ -0,0 +1,24 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; + +namespace LINGYUN.MicroService.OpenApi.Gateway; + +public static class AbpHostingHostBuilderExtensions +{ + public const string AppYarpJsonPath = "yarp.json"; + public static IHostBuilder AddYarpJson( + this IHostBuilder hostBuilder, + bool optional = true, + bool reloadOnChange = true, + string path = AppYarpJsonPath) + { + return hostBuilder.ConfigureAppConfiguration((_, builder) => + { + builder.AddJsonFile( + path: AppYarpJsonPath, + optional: optional, + reloadOnChange: reloadOnChange + ); + }); + } +} diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Controllers/HomeController.cs b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Controllers/HomeController.cs new file mode 100644 index 000000000..f50907a98 --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Controllers/HomeController.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc; + +namespace LINGYUN.MicroService.OpenApi.Gateway.Controllers; + +public class HomeController : AbpControllerBase +{ + public IActionResult Index() + { + return Redirect("/swagger/index.html"); + } +} diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Dockerfile b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Dockerfile new file mode 100644 index 000000000..587b073c2 --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Dockerfile @@ -0,0 +1,11 @@ +FROM mcr.microsoft.com/dotnet/aspnet:8.0 +LABEL maintainer="colin.in@foxmail.com" +WORKDIR /app + +COPY . /app + +EXPOSE 80/tcp +VOLUME [ "./app/Logs" ] +VOLUME [ "./app/Modules" ] + +ENTRYPOINT ["dotnet", "LINGYUN.MicroService.Internal.Gateway.dll"] diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/LINGYUN.MicroService.OpenApi.Gateway.csproj b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/LINGYUN.MicroService.OpenApi.Gateway.csproj new file mode 100644 index 000000000..7d7949d1d --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/LINGYUN.MicroService.OpenApi.Gateway.csproj @@ -0,0 +1,48 @@ + + + + Exe + net8.0 + LINGYUN.MicroService.Internal.Gateway + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + + diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/OpenApiGatewayModule.cs b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/OpenApiGatewayModule.cs new file mode 100644 index 000000000..e3297b588 --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/OpenApiGatewayModule.cs @@ -0,0 +1,243 @@ +using LINGYUN.Abp.AspNetCore.Mvc.Wrapper; +using LINGYUN.Abp.Identity.Session.AspNetCore; +using LINGYUN.Abp.OpenApi.Authorization; +using LINGYUN.Abp.Serilog.Enrichers.Application; +using LINGYUN.Abp.Serilog.Enrichers.UniqueId; +using LINGYUN.Abp.Wrapper; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Cors; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.WebSockets; +using Microsoft.Extensions.Caching.StackExchangeRedis; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; +using Microsoft.OpenApi.Models; +using StackExchange.Redis; +using System; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp; +using Volo.Abp.AspNetCore.Mvc; +using Volo.Abp.AspNetCore.Mvc.ApiExploring; +using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations; +using Volo.Abp.AspNetCore.Serilog; +using Volo.Abp.Autofac; +using Volo.Abp.Caching; +using Volo.Abp.Caching.StackExchangeRedis; +using Volo.Abp.Data; +using Volo.Abp.Modularity; +using Volo.Abp.Swashbuckle; +using Yarp.ReverseProxy.Configuration; + +namespace LINGYUN.MicroService.OpenApi.Gateway; + +[DependsOn( + typeof(AbpSerilogEnrichersApplicationModule), + typeof(AbpSerilogEnrichersUniqueIdModule), + typeof(AbpAutofacModule), + typeof(AbpDataModule), + typeof(AbpSwashbuckleModule), + typeof(AbpAspNetCoreSerilogModule), + typeof(AbpAspNetCoreMvcWrapperModule), + typeof(AbpOpenApiAuthorizationModule), + typeof(AbpCachingStackExchangeRedisModule), + typeof(AbpIdentitySessionAspNetCoreModule) +)] +public class OpenApiGatewayModule : AbpModule +{ + public static string ApplicationName { get; set; } = "Services.OpenApi.GateWay"; + public override void PreConfigureServices(ServiceConfigurationContext context) + { + AbpSerilogEnrichersConsts.ApplicationName = ApplicationName; + + PreConfigure(options => + { + // 以开放端口区别 + options.SnowflakeIdOptions.WorkerId = 0; + options.SnowflakeIdOptions.WorkerIdBits = 5; + options.SnowflakeIdOptions.DatacenterId = 1; + }); + } + + public override void ConfigureServices(ServiceConfigurationContext context) + { + var configuration = context.Services.GetConfiguration(); + var hostingEnvironment = context.Services.GetHostingEnvironment(); + + Configure(options => + { + options.IsEnabled = true; + }); + Configure(options => + { + options.ControllersToRemove.Add(typeof(AbpApiDefinitionController)); + options.ControllersToRemove.Add(typeof(AbpApplicationLocalizationController)); + options.ControllersToRemove.Add(typeof(AbpApplicationConfigurationController)); + options.ControllersToRemove.Add(typeof(AbpApplicationConfigurationScriptController)); + }); + + Configure(options => + { + configuration.GetSection("DistributedCache").Bind(options); + }); + + Configure(options => + { + var redisConfig = ConfigurationOptions.Parse(options.Configuration); + options.ConfigurationOptions = redisConfig; + options.InstanceName = configuration["Redis:InstanceName"]; + }); + + context.Services.AddAbpSwaggerGenWithOAuth( + authority: configuration["AuthServer:Authority"], + scopes: new Dictionary + { + {"Account", "Account API"}, + {"Identity", "Identity API"}, + {"IdentityServer", "Identity Server API"}, + {"BackendAdmin", "Backend Admin API"}, + {"Localization", "Localization API"}, + {"Platform", "Platform API"}, + {"RealtimeMessage", "RealtimeMessage API"}, + {"TaskManagement", "Task Management API"}, + {"Webhooks", "Webhooks API"}, + }, + options => + { + options.SwaggerDoc("v1", new OpenApiInfo { Title = "ApiGateway", Version = "v1" }); + options.DocInclusionPredicate((docName, description) => true); + options.CustomSchemaIds(type => type.FullName); + }); + context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + configuration.GetSection("AuthServer").Bind(options); + }); + + if (hostingEnvironment.IsProduction()) + { + var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); + context.Services + .AddDataProtection() + .SetApplicationName("LINGYUN.Abp.Application") + .PersistKeysToStackExchangeRedis(redis, "LINGYUN.Abp.Application:DataProtection:Protection-Keys"); + } + + context.Services.AddCors(options => + { + options.AddDefaultPolicy(builder => + { + builder + .WithOrigins( + configuration["App:CorsOrigins"] + .Split(",", StringSplitOptions.RemoveEmptyEntries) + .Select(o => o.Trim().RemovePostFix("/")) + .ToArray() + ) + .WithAbpExposedHeaders() + .WithAbpWrapExposedHeaders() + .SetIsOriginAllowedToAllowWildcardSubdomains() + .AllowAnyHeader() + .AllowAnyMethod() + .AllowCredentials(); + }); + }); + context.Services.AddWebSockets(options => + { + + }); + context.Services.AddHttpForwarder(); + context.Services.AddTelemetryListeners(); + + context.Services + .AddReverseProxy() + .ConfigureHttpClient((context, handler) => + { + handler.ActivityHeadersPropagator = null; + }) + .LoadFromConfig(configuration.GetSection("ReverseProxy")); + } + + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + var app = context.GetApplicationBuilder(); + var env = context.GetEnvironment(); + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + app.UseCorrelationId(); + app.UseCors(); + + // api签名 + app.UseOpenApiAuthorization(); + // 认证 + app.UseAuthentication(); + // 会话 + app.UseAbpSession(); + // 令牌 + app.UseDynamicClaims(); + // 授权 + app.UseAuthorization(); + + app.UseSwagger(); + app.UseSwaggerUI(options => + { + options.SwaggerEndpoint("/swagger/v1/swagger.json", "Open API Document"); + + var configuration = context.ServiceProvider.GetRequiredService(); + var logger = context.ServiceProvider.GetRequiredService>(); + var proxyConfigProvider = context.ServiceProvider.GetRequiredService(); + var yarpConfig = proxyConfigProvider.GetConfig(); + + var routedClusters = yarpConfig.Clusters + .SelectMany(t => t.Destinations, + (clusterId, destination) => new { clusterId.ClusterId, destination.Value }); + + var groupedClusters = routedClusters + .GroupBy(q => q.Value.Address) + .Select(t => t.First()) + .Distinct() + .ToList(); + + foreach (var clusterGroup in groupedClusters) + { + var routeConfig = yarpConfig.Routes.FirstOrDefault(q => + q.ClusterId == clusterGroup.ClusterId); + if (routeConfig == null) + { + logger.LogWarning($"Swagger UI: Couldn't find route configuration for {clusterGroup.ClusterId}..."); + continue; + } + + var swaggerEndpoint = clusterGroup.Value.Address; + if (clusterGroup.Value.Metadata != null && + clusterGroup.Value.Metadata.TryGetValue("SwaggerEndpoint", out var address) && + !address.IsNullOrWhiteSpace()) + { + swaggerEndpoint = address; + } + + options.SwaggerEndpoint($"{swaggerEndpoint}/swagger/v1/swagger.json", $"{routeConfig.RouteId} API"); + options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); + options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]); + } + }); + + // app.UseRewriter(new RewriteOptions().AddRedirect("^(|\\|\\s+)$", "/swagger")); + + app.UseRouting(); + app.UseAuditing(); + app.UseWebSockets(); + app.UseWebSocketsTelemetry(); + app.UseConfiguredEndpoints(endpoints => + { + endpoints.MapReverseProxy(); + }); + app.UseAbpSerilogEnrichers(); + } +} diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Program.cs b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Program.cs new file mode 100644 index 000000000..99cb5da26 --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Program.cs @@ -0,0 +1,59 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; +using System; +using System.Threading.Tasks; + +namespace LINGYUN.MicroService.OpenApi.Gateway; + +public class Program +{ + public static async Task Main(string[] args) + { + try + { + Log.Information("Starting OpenApi ApiGateway."); + var builder = WebApplication.CreateBuilder(args); + builder.Host.AddAppSettingsSecretsJson() + .UseAutofac() + .AddYarpJson() + .ConfigureAppConfiguration((context, config) => + { + var configuration = config.Build(); + var agileConfigEnabled = configuration["AgileConfig:IsEnabled"]; + if (agileConfigEnabled.IsNullOrEmpty() || bool.Parse(agileConfigEnabled)) + { + config.AddAgileConfig(new AgileConfig.Client.ConfigClient(configuration)); + } + }) + .UseSerilog((context, provider, config) => + { + config.ReadFrom.Configuration(context.Configuration); + }); + + await builder.AddApplicationAsync(options => + { + OpenApiGatewayModule.ApplicationName = Environment.GetEnvironmentVariable("APPLICATION_NAME") + ?? OpenApiGatewayModule.ApplicationName; + options.ApplicationName = OpenApiGatewayModule.ApplicationName; + }); + var app = builder.Build(); + await app.InitializeApplicationAsync(); + await app.RunAsync(); + + return 0; + } + catch (Exception ex) + { + Log.Fatal(ex, "Starting OpenApi ApiGateway terminated unexpectedly!"); + return 1; + } + finally + { + Log.CloseAndFlush(); + } + } +} diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Properties/launchSettings.json b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Properties/launchSettings.json new file mode 100644 index 000000000..739031cad --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/Properties/launchSettings.json @@ -0,0 +1,13 @@ +{ + "profiles": { + "LINGYUN.MicroService.Internal.Gateway": { + "commandName": "Project", + "launchBrowser": false, + "dotnetRunMessages": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "http://localhost:30000" + } + } +} \ No newline at end of file diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/appsettings.Development.json b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/appsettings.Development.json new file mode 100644 index 000000000..acec8c342 --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/appsettings.Development.json @@ -0,0 +1,100 @@ +{ + "AgileConfig": { + "IsEnabled": false, + "env": "DEV", + "appId": "LY.MicroService.Internal.Gateway", + "secret": "1q2w3E*", + "nodes": "http://127.0.0.1:5000", + "name": "BackendAdmin", + "tag": "BackendAdmin" + }, + "App": { + "CorsOrigins": "http://127.0.0.1:3100", + "ShowPii": true + }, + "ConnectionStrings": { + "Default": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", + "AbpIdentity": "Server=127.0.0.1;Database=IdentityServer-v70;User Id=root;Password=123456", + "AbpIdentityServer": "Server=127.0.0.1;Database=IdentityServer-v70;User Id=root;Password=123456", + "AbpSaas": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", + "AbpSettingManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", + "AbpFeatureManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", + "AbpPermissionManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", + "AbpLocalizationManagement": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456", + "AbpTextTemplating": "Server=127.0.0.1;Database=Platform-v70;User Id=root;Password=123456" + }, + "AuthServer": { + "Authority": "http://auth-server:44385/", + "Audience": "lingyun-abp-application", + "MapInboundClaims": false, + "RequireHttpsMetadata": false + }, + "OpenApi": { + "IsEnabled": true, + "AppDescriptors": [ + { + "AppName": "demo", + "AppKey": "demo", + "AppSecret": "97f9c13a-8931-40ff-b9e4-82fa848271d8", + "SignLifetime": 60 + } + ] + }, + "Logging": { + "Serilog": { + "Elasticsearch": { + "IndexFormat": "abp.dev.logging-{0:yyyy.MM.dd}" + } + } + }, + "AuditLogging": { + "Elasticsearch": { + "IndexPrefix": "abp.dev.auditing" + } + }, + "DistributedCache": { + "HideErrors": true, + "KeyPrefix": "LINGYUN.Abp.Application", + "GlobalCacheEntryOptions": { + "SlidingExpiration": "30:00:00", + "AbsoluteExpirationRelativeToNow": "60:00:00" + } + }, + "Redis": { + "IsEnabled": true, + "Configuration": "127.0.0.1,defaultDatabase=15", + "InstanceName": "LINGYUN.Abp.Application" + }, + "Elasticsearch": { + "NodeUris": "http://127.0.0.1:9200" + }, + "Serilog": { + "MinimumLevel": { + "Default": "Information", + "Override": { + "System": "Debug", + "Microsoft": "Debug", + "DotNetCore": "Warning", + "Yarp.ReverseProxy": "Debug" + } + }, + "WriteTo": [ + { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Debug", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "Elasticsearch", + "Args": { + "nodeUris": "http://127.0.0.1:9200", + "indexFormat": "abp.dev.logging-{0:yyyy.MM.dd}", + "autoRegisterTemplate": true, + "autoRegisterTemplateVersion": "ESv7" + } + } + ] + } +} diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/appsettings.json b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/appsettings.json new file mode 100644 index 000000000..d1667133d --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/appsettings.json @@ -0,0 +1,73 @@ +{ + "StringEncryption": { + "DefaultPassPhrase": "s46c5q55nxpeS8Ra", + "InitVectorBytes": "s83ng0abvd02js84", + "DefaultSalt": "sf&5)s3#" + }, + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "System": "Information", + "Microsoft": "Information", + "DotNetCore": "Information", + "Yarp.ReverseProxy": "Debug" + } + }, + "Enrich": [ "FromLogContext", "WithProcessId", "WithThreadId", "WithEnvironmentName", "WithMachineName", "WithApplicationName", "WithUniqueId" ], + "WriteTo": [ + { + "Name": "Console", + "Args": { + "restrictedToMinimumLevel": "Debug", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Debug-.log", + "restrictedToMinimumLevel": "Debug", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Info-.log", + "restrictedToMinimumLevel": "Information", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Warn-.log", + "restrictedToMinimumLevel": "Warning", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Error-.log", + "restrictedToMinimumLevel": "Error", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + }, + { + "Name": "File", + "Args": { + "path": "Logs/Fatal-.log", + "restrictedToMinimumLevel": "Fatal", + "rollingInterval": "Day", + "outputTemplate": "{Timestamp:yyyy-MM-dd HH:mm:ss} [{Level:u3}] [{SourceContext}] [{ProcessId}] [{ThreadId}] - {Message:lj}{NewLine}{Exception}" + } + } + ] + } +} diff --git a/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/yarp.json b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/yarp.json new file mode 100644 index 000000000..9ef5c1910 --- /dev/null +++ b/gateways/internal/LINGYUN.MicroService.Internal.ApiGateway/src/LINGYUN.MicroService.OpenApi.Gateway/yarp.json @@ -0,0 +1,434 @@ +{ + "ReverseProxy": { + "Routes": { + "abp-route": { + "ClusterId": "admin-api-cluster", + "Match": { + "Path": "/api/abp/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "auth-server-route": { + "ClusterId": "auth-server-cluster", + "Match": { + "Path": "/connect/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "account-route": { + "ClusterId": "auth-server-api-cluster", + "Match": { + "Path": "/api/account/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "identity-route": { + "ClusterId": "auth-server-api-cluster", + "Match": { + "Path": "/api/identity/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "identity-server-route": { + "ClusterId": "auth-server-api-cluster", + "Match": { + "Path": "/api/identity-server/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "cache-management-route": { + "ClusterId": "admin-api-cluster", + "Match": { + "Path": "/api/caching-management/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "saas-route": { + "ClusterId": "admin-api-cluster", + "Match": { + "Path": "/api/saas/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "auditing-route": { + "ClusterId": "admin-api-cluster", + "Match": { + "Path": "/api/auditing/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "data-protected-route": { + "ClusterId": "admin-api-cluster", + "Match": { + "Path": "/api/data-protection-management/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "text-template-route": { + "ClusterId": "admin-api-cluster", + "Match": { + "Path": "/api/text-templating/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "feature-management-route": { + "ClusterId": "admin-api-cluster", + "Match": { + "Path": "/api/feature-management/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "permission-management-route": { + "ClusterId": "admin-api-cluster", + "Match": { + "Path": "/api/permission-management/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "setting-management-route": { + "ClusterId": "admin-api-cluster", + "Match": { + "Path": "/api/setting-management/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "localization-management-route": { + "ClusterId": "localization-api-cluster", + "Match": { + "Path": "/api/localization/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "im-route": { + "ClusterId": "messages-api-cluster", + "Match": { + "Path": "/api/im/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "notifications-route": { + "ClusterId": "messages-api-cluster", + "Match": { + "Path": "/api/notifications/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "signalr-route": { + "ClusterId": "messages-api-cluster", + "Match": { + "Path": "/signalr-hubs/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + }, + { + "RequestHeadersCopy": true + }, + { + "ResponseHeadersCopy": true + } + ] + }, + "webhooks-management-route": { + "ClusterId": "webhooks-api-cluster", + "Match": { + "Path": "/api/webhooks/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "task-management-route": { + "ClusterId": "tasks-api-cluster", + "Match": { + "Path": "/api/task-management/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "platform-route": { + "ClusterId": "platform-api-cluster", + "Match": { + "Path": "/api/platform/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "oss-route": { + "ClusterId": "platform-api-cluster", + "Match": { + "Path": "/api/oss-management/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + }, + "files-route": { + "ClusterId": "platform-api-cluster", + "Match": { + "Path": "/api/files/{**everything}" + }, + "Transforms": [ + { + "HeaderPrefix": "X-Forwarded-", + "X-Forwarded": "Append" + }, + { + "ResponseHeadersAllowed": "_AbpWrapResult;_AbpDontWrapResult;_AbpErrorFormat" + } + ] + } + }, + "Clusters": { + "auth-server-cluster": { + "Destinations": { + "destination1": { + "Address": "http://auth-server:44385", + "Metadata": { + "SwaggerEndpoint": "http://127.0.0.1:44385" + } + } + } + }, + "auth-server-api-cluster": { + "Destinations": { + "destination1": { + "Address": "http://auth-server-api:30015", + "Metadata": { + "SwaggerEndpoint": "http://127.0.0.1:30015" + } + } + } + }, + "admin-api-cluster": { + "Destinations": { + "destination1": { + "Address": "http://admin-api:30010", + "Metadata": { + "SwaggerEndpoint": "http://127.0.0.1:30010" + } + } + } + }, + "localization-api-cluster": { + "Destinations": { + "destination1": { + "Address": "http://localization-api:30030", + "Metadata": { + "SwaggerEndpoint": "http://127.0.0.1:30030" + } + } + } + }, + "messages-api-cluster": { + "Destinations": { + "destination1": { + "Address": "http://messages-api:30020", + "Metadata": { + "SwaggerEndpoint": "http://127.0.0.1:30020" + } + } + } + }, + "webhooks-api-cluster": { + "Destinations": { + "destination1": { + "Address": "http://webhooks-api:30045", + "Metadata": { + "SwaggerEndpoint": "http://127.0.0.1:30045" + } + } + } + }, + "tasks-api-cluster": { + "Destinations": { + "destination1": { + "Address": "http://tasks-api:30040", + "Metadata": { + "SwaggerEndpoint": "http://127.0.0.1:30040" + } + } + } + }, + "platform-api-cluster": { + "Destinations": { + "destination1": { + "Address": "http://platform-api:30025", + "Metadata": { + "SwaggerEndpoint": "http://127.0.0.1:30025" + } + } + } + }, + "workflow-api-cluster": { + "Destinations": { + "destination1": { + "Address": "http://workflow-api:30050", + "Metadata": { + "SwaggerEndpoint": "http://127.0.0.1:30050" + } + } + } + } + } + } +} \ No newline at end of file