2019-12-23 16:32:06 +08:00
|
|
|
|
using System;
|
2024-09-08 14:42:51 +08:00
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Reflection;
|
2024-12-23 20:26:21 +08:00
|
|
|
|
using System.Text.Json;
|
2025-01-16 22:05:59 +08:00
|
|
|
|
using Hangfire;
|
|
|
|
|
|
using Hangfire.Console;
|
|
|
|
|
|
using Hangfire.Redis.StackExchange;
|
2020-08-05 15:29:56 +08:00
|
|
|
|
using SimApi.Helpers;
|
2019-12-23 16:32:06 +08:00
|
|
|
|
using Microsoft.AspNetCore.Builder;
|
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
2025-12-18 09:08:35 +08:00
|
|
|
|
using Microsoft.OpenApi;
|
2020-08-05 15:29:56 +08:00
|
|
|
|
using SimApi.Middlewares;
|
2020-12-29 17:18:02 +08:00
|
|
|
|
using Microsoft.AspNetCore.HttpOverrides;
|
2025-11-01 18:40:51 +08:00
|
|
|
|
using Microsoft.AspNetCore.Mvc;
|
2024-07-26 05:03:28 +08:00
|
|
|
|
using Microsoft.Extensions.Hosting;
|
2021-06-28 05:36:54 +08:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2024-09-08 14:42:51 +08:00
|
|
|
|
using SimApi.Attributes;
|
2024-08-19 03:39:35 +08:00
|
|
|
|
using SimApi.CoceSdk;
|
2024-04-16 06:57:56 +08:00
|
|
|
|
using SimApi.Configurations;
|
2026-05-04 15:35:47 +08:00
|
|
|
|
using SimApi.Interfaces;
|
2021-06-28 05:36:54 +08:00
|
|
|
|
using SimApi.Logger;
|
2025-11-02 22:14:34 +08:00
|
|
|
|
using SimApi.SwaggerFilters;
|
2026-05-03 19:34:47 +08:00
|
|
|
|
using StackExchange.Redis;
|
2019-12-23 16:32:06 +08:00
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
namespace SimApi;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 加入系统的扩展信息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public static class SimApiExtensions
|
2019-12-23 16:32:06 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
//**********快捷添加**************
|
|
|
|
|
|
public static IServiceCollection AddSimApi(this IServiceCollection builder,
|
2024-08-03 19:19:42 +08:00
|
|
|
|
Action<SimApiOptions>? options = null)
|
2019-12-23 16:32:06 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
var simApiOptions = new SimApiOptions();
|
|
|
|
|
|
options?.Invoke(simApiOptions);
|
2025-01-16 22:05:59 +08:00
|
|
|
|
if (simApiOptions.RedisConfiguration != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AddStackExchangeRedisCache(x => x.Configuration = simApiOptions.RedisConfiguration);
|
2026-05-03 19:34:47 +08:00
|
|
|
|
builder.AddSingleton<IConnectionMultiplexer>(_ =>
|
|
|
|
|
|
ConnectionMultiplexer.Connect(simApiOptions.RedisConfiguration));
|
2025-01-16 22:05:59 +08:00
|
|
|
|
builder.AddSingleton<SimApiCache>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
if (simApiOptions.EnableLogger)
|
2019-12-23 16:32:06 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
builder.AddLogging(logger =>
|
2022-08-05 02:20:27 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
logger.ClearProviders();
|
|
|
|
|
|
logger.AddProvider(new SimApiLoggerProvider());
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2024-04-16 06:57:56 +08:00
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
// 是否使用 AUTH
|
|
|
|
|
|
if (simApiOptions.EnableSimApiAuth)
|
|
|
|
|
|
{
|
2024-03-24 17:40:48 +08:00
|
|
|
|
builder.AddSingleton<SimApiAuth>();
|
2024-03-23 07:29:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-19 03:39:35 +08:00
|
|
|
|
if (simApiOptions.EnableCoceSdk)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AddSingleton<CoceApp>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-04 15:35:47 +08:00
|
|
|
|
var simApiAuthChecker = typeof(ISimApiAuthChecker);
|
|
|
|
|
|
var stackTrace = new StackTrace();
|
|
|
|
|
|
var callingMethod = stackTrace.GetFrame(stackTrace.FrameCount - 1)?.GetMethod();
|
|
|
|
|
|
var callerAssembly = callingMethod?.DeclaringType?.Assembly;
|
|
|
|
|
|
var callerTypes = callerAssembly?.GetTypes() ?? [];
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var type in callerTypes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (type is { IsClass: true, IsAbstract: false } && simApiAuthChecker.IsAssignableFrom(type))
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AddScoped(simApiAuthChecker, type);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-16 22:05:59 +08:00
|
|
|
|
if (simApiOptions.EnableJob)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AddHangfire(x =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var redisOption = new RedisStorageOptions();
|
|
|
|
|
|
if (simApiOptions.SimApiJobOptions.Database.HasValue)
|
|
|
|
|
|
{
|
|
|
|
|
|
redisOption.Db = simApiOptions.SimApiJobOptions.Database.Value;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
x.UseRedisStorage(simApiOptions.SimApiJobOptions.RedisConfiguration ??
|
|
|
|
|
|
simApiOptions.RedisConfiguration, redisOption);
|
|
|
|
|
|
x.UseConsole();
|
|
|
|
|
|
});
|
|
|
|
|
|
foreach (var server in simApiOptions.SimApiJobOptions.Servers)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AddHangfireServer(hfs =>
|
|
|
|
|
|
{
|
|
|
|
|
|
hfs.Queues = server.Queues;
|
|
|
|
|
|
hfs.WorkerCount = server.WorkerNum;
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
if (simApiOptions.EnableCors)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AddCors(cors => cors.AddPolicy("any",
|
|
|
|
|
|
policy => { policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin(); }));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (simApiOptions.EnableSynapse)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AddSingleton<Synapse>();
|
2026-05-04 15:35:47 +08:00
|
|
|
|
foreach (var type in callerTypes)
|
2024-09-08 14:42:51 +08:00
|
|
|
|
{
|
|
|
|
|
|
var methodsWithSynapse = type.GetMethods()
|
|
|
|
|
|
.Where(m => m.GetCustomAttribute<SynapseRpcAttribute>() != null ||
|
|
|
|
|
|
m.GetCustomAttribute<SynapseEventAttribute>() != null);
|
|
|
|
|
|
if (!methodsWithSynapse.Any()) continue;
|
|
|
|
|
|
builder.AddScoped(type);
|
|
|
|
|
|
}
|
2024-03-23 07:29:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用SimApiDoc
|
|
|
|
|
|
if (simApiOptions.EnableSimApiDoc)
|
|
|
|
|
|
{
|
|
|
|
|
|
var docOptions = simApiOptions.SimApiDocOptions;
|
|
|
|
|
|
builder.AddSwaggerGen(x =>
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var group in docOptions.ApiGroups)
|
2022-08-05 02:20:27 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
x.SwaggerDoc(group.Id, new OpenApiInfo
|
|
|
|
|
|
{
|
|
|
|
|
|
Title = group.Name,
|
|
|
|
|
|
Description = group.Description
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
2025-12-23 06:00:33 +08:00
|
|
|
|
|
2025-12-23 07:20:34 +08:00
|
|
|
|
x.CustomSchemaIds(type =>
|
|
|
|
|
|
{
|
2025-12-23 08:18:11 +08:00
|
|
|
|
// 递归解析类型名称(处理嵌套泛型/数组/可空 + 保证唯一性)
|
|
|
|
|
|
string GetSimpleTypeName(Type t, int depth = 0)
|
2025-12-23 07:20:34 +08:00
|
|
|
|
{
|
2025-12-23 08:18:11 +08:00
|
|
|
|
// 防止无限递归
|
|
|
|
|
|
if (depth > 5) return t.Name.Split('`')[0];
|
|
|
|
|
|
|
|
|
|
|
|
// 处理数组类型
|
2025-12-23 07:20:34 +08:00
|
|
|
|
if (t.IsArray)
|
|
|
|
|
|
{
|
|
|
|
|
|
var elementType = t.GetElementType();
|
2026-04-26 04:09:35 +08:00
|
|
|
|
return $"{GetSimpleTypeName(elementType!, depth + 1)}[]";
|
2025-12-23 07:20:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-23 08:18:11 +08:00
|
|
|
|
// 处理可空类型
|
|
|
|
|
|
if (Nullable.GetUnderlyingType(t) != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var underlyingType = Nullable.GetUnderlyingType(t);
|
2026-04-26 04:09:35 +08:00
|
|
|
|
return GetSimpleTypeName(underlyingType!, depth + 1);
|
2025-12-23 08:18:11 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理泛型类型(递归解析嵌套泛型)
|
|
|
|
|
|
if (t.IsGenericType)
|
|
|
|
|
|
{
|
|
|
|
|
|
var genericBaseName = t.GetGenericTypeDefinition().Name.Split('`')[0];
|
|
|
|
|
|
var genericArgs = t.GetGenericArguments()
|
|
|
|
|
|
.Select(arg => GetSimpleTypeName(arg, depth + 1))
|
|
|
|
|
|
.Where(arg => !string.IsNullOrEmpty(arg))
|
|
|
|
|
|
.ToArray();
|
|
|
|
|
|
return $"{genericBaseName}<{string.Join(",", genericArgs)}>";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理基础类型(小写)
|
2025-12-23 07:20:34 +08:00
|
|
|
|
if (t.IsPrimitive || t == typeof(string) || t == typeof(DateTime) || t == typeof(Guid))
|
|
|
|
|
|
{
|
|
|
|
|
|
return t.Name switch
|
|
|
|
|
|
{
|
|
|
|
|
|
"String" => "string",
|
|
|
|
|
|
"Int32" => "int",
|
|
|
|
|
|
"Int64" => "long",
|
|
|
|
|
|
"Boolean" => "boolean",
|
2025-12-23 08:18:11 +08:00
|
|
|
|
"DateTime" => "datetime",
|
|
|
|
|
|
"Guid" => "guid",
|
|
|
|
|
|
_ => t.Name.ToLower()
|
2025-12-23 07:20:34 +08:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-23 08:18:11 +08:00
|
|
|
|
// 核心修复:生成唯一名称(处理嵌套类/同名不同类)
|
|
|
|
|
|
var typeName = t.Name;
|
|
|
|
|
|
|
|
|
|
|
|
// 步骤1:处理嵌套类(如 ApplicationDto+ApplicationEditRequest → ApplicationDto_ApplicationEditRequest)
|
|
|
|
|
|
if (t.DeclaringType != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
typeName = $"{GetSimpleTypeName(t.DeclaringType)}.{typeName}";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 步骤2:(可选)处理同命名空间下的同名类(拼接命名空间前缀,避免全局重复)
|
|
|
|
|
|
// 如需更严格的唯一性,取消注释下面这行
|
|
|
|
|
|
// typeName = $"{t.Namespace?.Replace(".", "_")}_{typeName}";
|
|
|
|
|
|
|
|
|
|
|
|
return typeName;
|
2025-12-23 07:20:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-23 08:18:11 +08:00
|
|
|
|
// 根调用:解析当前类型
|
|
|
|
|
|
var uniqueSchemaId = GetSimpleTypeName(type);
|
|
|
|
|
|
// 可选:移除特殊字符(如 $、+),避免 Swagger 解析问题
|
|
|
|
|
|
return uniqueSchemaId.Replace("$", "").Replace("+", "_");
|
2025-12-23 07:20:34 +08:00
|
|
|
|
});
|
2025-11-02 22:14:34 +08:00
|
|
|
|
x.OperationFilter<SimApiResponseOperationFilter>();
|
|
|
|
|
|
x.OperationFilter<SimApiSignOperationFilter>();
|
|
|
|
|
|
x.OperationFilter<AesBodyOperationFilter>();
|
2025-11-09 19:36:21 +08:00
|
|
|
|
x.SchemaFilter<GlobalDynamicObjectSchemaFilter>();
|
2025-12-19 13:37:58 +08:00
|
|
|
|
x.DocumentFilter<RemoveEmptyTagsFilter>();
|
2025-11-01 15:40:55 +08:00
|
|
|
|
if (simApiOptions.EnableSimApiAuth)
|
|
|
|
|
|
{
|
|
|
|
|
|
x.OperationFilter<SimApiAuthOperationFilter>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-01 18:40:51 +08:00
|
|
|
|
x.DocInclusionPredicate((docName, apiDesc) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取接口标记的 GroupName(未标记则为 null)
|
|
|
|
|
|
var actionGroupName = apiDesc.ActionDescriptor.EndpointMetadata
|
|
|
|
|
|
.OfType<ApiExplorerSettingsAttribute>()
|
|
|
|
|
|
.FirstOrDefault()?.GroupName;
|
|
|
|
|
|
|
|
|
|
|
|
// 情况1:接口未标记任何 GroupName(actionGroupName 为 null)
|
|
|
|
|
|
if (actionGroupName == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return docName == "api"; // 未分组接口只属于默认分组v1
|
|
|
|
|
|
}
|
2025-11-01 21:38:55 +08:00
|
|
|
|
|
2025-11-01 18:40:51 +08:00
|
|
|
|
return docName == actionGroupName;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
x.EnableAnnotations();
|
|
|
|
|
|
var haveOauth = false;
|
|
|
|
|
|
var oauthFlows = new OpenApiOAuthFlows();
|
|
|
|
|
|
foreach (var auth in docOptions.ApiAuth.Type)
|
2021-06-03 13:43:46 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
switch (auth)
|
2021-06-03 13:43:46 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
case "SimApiAuth":
|
2025-12-23 07:20:34 +08:00
|
|
|
|
x.AddSecurityDefinition("SimApiAuth",
|
2025-11-01 15:40:55 +08:00
|
|
|
|
new OpenApiSecurityScheme
|
2021-06-03 13:43:46 +08:00
|
|
|
|
{
|
2025-11-01 15:40:55 +08:00
|
|
|
|
Name = "Token",
|
2025-12-23 06:00:33 +08:00
|
|
|
|
In = ParameterLocation.Header,
|
|
|
|
|
|
Type = SecuritySchemeType.ApiKey
|
2025-11-01 15:40:55 +08:00
|
|
|
|
});
|
2024-03-23 07:29:43 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "ClientCredentials":
|
|
|
|
|
|
oauthFlows.ClientCredentials = new OpenApiOAuthFlow
|
|
|
|
|
|
{
|
|
|
|
|
|
TokenUrl = new Uri(docOptions.ApiAuth.TokenUrl, UriKind.RelativeOrAbsolute),
|
|
|
|
|
|
Scopes = docOptions.ApiAuth.Scopes
|
|
|
|
|
|
};
|
|
|
|
|
|
haveOauth = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "Implicit":
|
|
|
|
|
|
oauthFlows.Implicit = new OpenApiOAuthFlow
|
|
|
|
|
|
{
|
|
|
|
|
|
AuthorizationUrl = new Uri(docOptions.ApiAuth.AuthorizationUrl,
|
|
|
|
|
|
UriKind.RelativeOrAbsolute),
|
|
|
|
|
|
Scopes = docOptions.ApiAuth.Scopes
|
|
|
|
|
|
};
|
|
|
|
|
|
haveOauth = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "AuthorizationCode":
|
|
|
|
|
|
oauthFlows.AuthorizationCode = new OpenApiOAuthFlow
|
|
|
|
|
|
{
|
|
|
|
|
|
TokenUrl = new Uri(docOptions.ApiAuth.TokenUrl, UriKind.RelativeOrAbsolute),
|
|
|
|
|
|
AuthorizationUrl = new Uri(docOptions.ApiAuth.AuthorizationUrl,
|
|
|
|
|
|
UriKind.RelativeOrAbsolute),
|
|
|
|
|
|
Scopes = docOptions.ApiAuth.Scopes
|
|
|
|
|
|
};
|
|
|
|
|
|
haveOauth = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "Password":
|
|
|
|
|
|
oauthFlows.Password = new OpenApiOAuthFlow
|
|
|
|
|
|
{
|
|
|
|
|
|
TokenUrl = new Uri(docOptions.ApiAuth.TokenUrl, UriKind.RelativeOrAbsolute),
|
|
|
|
|
|
Scopes = docOptions.ApiAuth.Scopes
|
|
|
|
|
|
};
|
|
|
|
|
|
haveOauth = true;
|
|
|
|
|
|
break;
|
2021-06-03 13:43:46 +08:00
|
|
|
|
}
|
2024-03-23 07:29:43 +08:00
|
|
|
|
}
|
2021-06-03 13:43:46 +08:00
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
if (haveOauth)
|
|
|
|
|
|
{
|
|
|
|
|
|
x.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
|
2021-06-03 13:43:46 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
Type = SecuritySchemeType.OAuth2,
|
|
|
|
|
|
Flows = oauthFlows,
|
|
|
|
|
|
Description = docOptions.ApiAuth.Description,
|
|
|
|
|
|
In = ParameterLocation.Header
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2020-02-04 16:05:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
// 使用Header转发,应对代理后获取真实ip
|
|
|
|
|
|
if (simApiOptions.EnableForwardHeaders)
|
2020-02-04 16:05:09 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
builder.Configure<ForwardedHeadersOptions>(fwOptions =>
|
2021-06-03 17:16:55 +08:00
|
|
|
|
{
|
2024-03-23 07:29:43 +08:00
|
|
|
|
fwOptions.ForwardedHeaders = ForwardedHeaders.All;
|
|
|
|
|
|
fwOptions.KnownNetworks.Clear();
|
|
|
|
|
|
fwOptions.KnownProxies.Clear();
|
|
|
|
|
|
});
|
2019-12-23 16:32:06 +08:00
|
|
|
|
}
|
2024-03-23 07:29:43 +08:00
|
|
|
|
|
|
|
|
|
|
if (simApiOptions.EnableLowerUrl)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AddRouting(rOptions => rOptions.LowercaseUrls = true);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (simApiOptions.EnableSimApiStorage)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.AddHttpContextAccessor();
|
|
|
|
|
|
builder.AddSingleton<SimApiStorage>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-23 22:11:00 +08:00
|
|
|
|
if (simApiOptions.EnableSimApiResponseFilter)
|
2024-12-23 20:26:21 +08:00
|
|
|
|
{
|
|
|
|
|
|
builder.AddControllers(opt => opt.Filters.Add<SimApiResponseFilter>())
|
2025-05-14 06:26:10 +08:00
|
|
|
|
.AddJsonOptions(opt =>
|
|
|
|
|
|
{
|
|
|
|
|
|
opt.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
|
|
|
|
|
});
|
2024-12-23 20:26:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
builder.AddSingleton(simApiOptions);
|
|
|
|
|
|
return builder;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-26 05:03:28 +08:00
|
|
|
|
public static IHost UseSimApi(this IHost builder)
|
|
|
|
|
|
{
|
2024-08-19 03:39:35 +08:00
|
|
|
|
var options = builder.Services.GetRequiredService<SimApiOptions>();
|
2024-07-26 05:03:28 +08:00
|
|
|
|
|
|
|
|
|
|
var logger = builder.Services.GetRequiredService<ILogger<SimApiOptions>>();
|
|
|
|
|
|
|
|
|
|
|
|
logger.LogInformation("当前时区: {LocalId}", TimeZoneInfo.Local.Id);
|
2025-11-01 15:40:55 +08:00
|
|
|
|
logger.LogInformation("主应用版本: {AppVersion}\nSimApi版本: {SimApiVersion}", SimApiUtil.AppVersion,
|
|
|
|
|
|
SimApiUtil.SimApiVersion);
|
2024-08-19 03:39:35 +08:00
|
|
|
|
|
2025-01-16 22:05:59 +08:00
|
|
|
|
if (options.RedisConfiguration != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置 RedisCache ...");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-26 05:03:28 +08:00
|
|
|
|
//请求一下检测存储错误
|
|
|
|
|
|
if (options.EnableSimApiStorage)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置SimApiStorage...");
|
|
|
|
|
|
builder.Services.GetService<SimApiStorage>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-08-19 03:39:35 +08:00
|
|
|
|
if (options.EnableCoceSdk)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置CoceAppSdk...\nApi入口: {ApiUrl}\nAuth入口:{AuthUrl}n\nAppId: {AppId}",
|
|
|
|
|
|
options.CoceSdkOptions.ApiEndpoint, options.CoceSdkOptions.AuthEndpoint,
|
|
|
|
|
|
options.CoceSdkOptions.AppId);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-26 05:03:28 +08:00
|
|
|
|
if (options.EnableSynapse)
|
|
|
|
|
|
{
|
|
|
|
|
|
var synapse = builder.Services.GetRequiredService<Synapse>();
|
|
|
|
|
|
synapse.Init();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-16 22:05:59 +08:00
|
|
|
|
if (options.EnableJob)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置 SimApiJob ...");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-26 05:03:28 +08:00
|
|
|
|
return builder;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 使用所有SimApi自定义中间件
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="builder"></param>
|
|
|
|
|
|
/// <returns></returns>
|
2024-07-26 19:18:59 +08:00
|
|
|
|
public static WebApplication UseSimApi(this WebApplication builder)
|
2024-03-23 07:29:43 +08:00
|
|
|
|
{
|
2024-07-26 19:18:59 +08:00
|
|
|
|
var options = builder.Services.GetRequiredService<SimApiOptions>();
|
|
|
|
|
|
var logger = builder.Services.GetRequiredService<ILogger<SimApiOptions>>();
|
2025-01-16 22:05:59 +08:00
|
|
|
|
UseSimApi((IHost)builder);
|
2024-03-23 07:29:43 +08:00
|
|
|
|
if (options.EnableForwardHeaders)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置ForwardedHeaders...");
|
|
|
|
|
|
builder.UseForwardedHeaders();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (options.EnableCors)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置Cors全部允许...");
|
|
|
|
|
|
builder.UseCors("any");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-16 22:05:59 +08:00
|
|
|
|
if (options.EnableSimApiResponseFilter)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置SimApiResponseFilter...");
|
2025-01-17 01:30:13 +08:00
|
|
|
|
builder.MapControllers();
|
2025-01-16 22:05:59 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-04 15:35:47 +08:00
|
|
|
|
var checkers = builder.Services.CreateScope().ServiceProvider.GetServices<ISimApiAuthChecker>().ToArray();
|
|
|
|
|
|
if (checkers.Length != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var msg = checkers.Aggregate("开始配置SimApiAuthChecker...",
|
|
|
|
|
|
(current, checker) => current + $"\n|- {checker.GetType().FullName}");
|
|
|
|
|
|
logger.LogInformation(msg);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-03 19:34:47 +08:00
|
|
|
|
if (options.EnableSimApiGateAuth)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置SimApiGateAuth...");
|
|
|
|
|
|
if (string.IsNullOrEmpty(options.SimApiGateAuthOptions.AppId) ||
|
|
|
|
|
|
string.IsNullOrEmpty(options.SimApiGateAuthOptions.AppKey))
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogCritical("必须配置Gate的AppId和AppKey才能启用SimApiGateAuth");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.UseMiddleware<SimApiGateAuthMiddleware>();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-04 15:35:47 +08:00
|
|
|
|
builder.MapControllerRoute(name: "CheckLogin", pattern: "/auth/check",
|
|
|
|
|
|
defaults: new
|
|
|
|
|
|
{
|
|
|
|
|
|
controller = "SimApiCommon",
|
|
|
|
|
|
action = "CheckLogin"
|
|
|
|
|
|
});
|
2024-03-23 07:29:43 +08:00
|
|
|
|
if (options.EnableSimApiAuth)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置SimApiAuth...");
|
|
|
|
|
|
builder.UseMiddleware<SimApiAuthMiddleware>();
|
2024-08-19 03:39:35 +08:00
|
|
|
|
builder.MapControllerRoute(name: "GetUserInfo", pattern: "/user/info",
|
2025-05-14 06:26:10 +08:00
|
|
|
|
defaults: new
|
|
|
|
|
|
{
|
2025-11-01 21:38:55 +08:00
|
|
|
|
controller = "SimApiAuth",
|
2025-05-14 06:26:10 +08:00
|
|
|
|
action = "UserInfo"
|
|
|
|
|
|
});
|
2026-05-04 15:35:47 +08:00
|
|
|
|
|
2024-08-19 03:39:35 +08:00
|
|
|
|
builder.MapControllerRoute(name: "Logout", pattern: "/auth/logout",
|
2025-05-14 06:26:10 +08:00
|
|
|
|
defaults: new
|
|
|
|
|
|
{
|
2025-11-01 21:38:55 +08:00
|
|
|
|
controller = "SimApiAuth",
|
2025-05-14 06:26:10 +08:00
|
|
|
|
action = "Logout"
|
|
|
|
|
|
});
|
2024-08-19 03:39:35 +08:00
|
|
|
|
if (options.EnableCoceSdk)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置CoceAppSdk...\nApi入口: {ApiUrl}\nAuth入口:{AuthUrl}n\nAppId: {AppId}",
|
|
|
|
|
|
options.CoceSdkOptions.ApiEndpoint, options.CoceSdkOptions.AuthEndpoint,
|
|
|
|
|
|
options.CoceSdkOptions.AppId);
|
|
|
|
|
|
builder.MapControllerRoute(name: "LoginUseCoce", pattern: "/auth/login",
|
2025-05-14 06:26:10 +08:00
|
|
|
|
defaults: new
|
|
|
|
|
|
{
|
|
|
|
|
|
controller = "Coce",
|
|
|
|
|
|
action = "Login"
|
|
|
|
|
|
});
|
2024-08-19 03:39:35 +08:00
|
|
|
|
builder.MapControllerRoute(name: "LoginUseCoce", pattern: "/user/groups",
|
2025-05-14 06:26:10 +08:00
|
|
|
|
defaults: new
|
|
|
|
|
|
{
|
|
|
|
|
|
controller = "Coce",
|
|
|
|
|
|
action = "ListGroups"
|
|
|
|
|
|
});
|
2024-08-19 03:39:35 +08:00
|
|
|
|
builder.MapControllerRoute(name: "LoginUseCoce", pattern: "/auth/config",
|
2025-05-14 06:26:10 +08:00
|
|
|
|
defaults: new
|
|
|
|
|
|
{
|
|
|
|
|
|
controller = "Coce",
|
|
|
|
|
|
action = "GetConfig"
|
|
|
|
|
|
});
|
2024-08-19 03:39:35 +08:00
|
|
|
|
}
|
2024-03-23 07:29:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-01 15:40:55 +08:00
|
|
|
|
if (options.EnableVersionUrl)
|
|
|
|
|
|
{
|
|
|
|
|
|
builder.MapControllerRoute(name: "Versions", pattern: "/versions",
|
|
|
|
|
|
defaults: new
|
|
|
|
|
|
{
|
|
|
|
|
|
controller = "SimApiCommon",
|
|
|
|
|
|
action = "Versions"
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-23 07:29:43 +08:00
|
|
|
|
if (options.EnableSimApiDoc)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置SimApiDoc...");
|
|
|
|
|
|
var docOptions = options.SimApiDocOptions;
|
2025-11-01 15:40:55 +08:00
|
|
|
|
builder.UseSwagger(x => x.RouteTemplate = "/swagger/{documentName}.json")
|
|
|
|
|
|
.UseSwaggerUI(x =>
|
2024-03-23 07:29:43 +08:00
|
|
|
|
{
|
2025-11-01 15:40:55 +08:00
|
|
|
|
x.DocumentTitle = docOptions.DocumentTitle;
|
|
|
|
|
|
foreach (var group in docOptions.ApiGroups)
|
|
|
|
|
|
{
|
|
|
|
|
|
x.SwaggerEndpoint($"/swagger/{group.Id}.json", name: group.Name);
|
|
|
|
|
|
}
|
2024-03-23 07:29:43 +08:00
|
|
|
|
|
2025-11-01 15:40:55 +08:00
|
|
|
|
x.SupportedSubmitMethods(docOptions.SupportedMethod);
|
|
|
|
|
|
x.DisplayRequestDuration();
|
|
|
|
|
|
});
|
2024-03-23 07:29:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (options.EnableSimApiException)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置SimApiException...");
|
|
|
|
|
|
builder.UseMiddleware<SimApiExceptionMiddleware>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (options.EnableLowerUrl)
|
|
|
|
|
|
{
|
|
|
|
|
|
logger.LogInformation("开始配置使用URL小写...");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-16 22:05:59 +08:00
|
|
|
|
if (options is { EnableJob: true, SimApiJobOptions.DashboardUrl: not null })
|
2024-03-23 07:29:43 +08:00
|
|
|
|
{
|
2025-01-16 22:05:59 +08:00
|
|
|
|
logger.LogInformation("开始配置 SimApiJob Web控制台...");
|
|
|
|
|
|
builder.UseHangfireDashboard(options.SimApiJobOptions.DashboardUrl, new DashboardOptions
|
|
|
|
|
|
{
|
|
|
|
|
|
Authorization =
|
|
|
|
|
|
[
|
|
|
|
|
|
new SimApiJobWebAuth(options.SimApiJobOptions.DashboardAuthUser,
|
|
|
|
|
|
options.SimApiJobOptions.DashboardAuthPass)
|
|
|
|
|
|
]
|
|
|
|
|
|
});
|
2024-03-23 07:29:43 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return builder;
|
2019-12-23 16:32:06 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|