HostApp.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709
  1. using AspNetCoreRateLimit;
  2. using Autofac;
  3. using IdentityServer4.AccessTokenValidation;
  4. using Microsoft.AspNetCore.Authentication;
  5. using Microsoft.AspNetCore.Authentication.JwtBearer;
  6. using Microsoft.AspNetCore.Builder;
  7. using Microsoft.AspNetCore.Hosting;
  8. using Microsoft.AspNetCore.Http;
  9. using Microsoft.Extensions.Configuration;
  10. using Microsoft.Extensions.DependencyInjection;
  11. using Microsoft.Extensions.DependencyInjection.Extensions;
  12. using Microsoft.Extensions.Hosting;
  13. using Microsoft.Extensions.DependencyModel;
  14. using Microsoft.IdentityModel.Tokens;
  15. using Microsoft.OpenApi.Models;
  16. using Newtonsoft.Json;
  17. using Newtonsoft.Json.Serialization;
  18. using System;
  19. using System.Collections.Generic;
  20. using System.IdentityModel.Tokens.Jwt;
  21. using System.Linq;
  22. using System.Reflection;
  23. using System.Text;
  24. using Mapster;
  25. using Yitter.IdGenerator;
  26. using FluentValidation;
  27. using FluentValidation.AspNetCore;
  28. using ZhonTai.Admin.Core.Auth;
  29. using ZhonTai.Admin.Tools.Cache;
  30. using ZhonTai.Common.Helpers;
  31. using ZhonTai.Admin.Core.Db;
  32. using ZhonTai.Admin.Core.Extensions;
  33. using ZhonTai.Admin.Core.Filters;
  34. using ZhonTai.Admin.Core.Logs;
  35. using ZhonTai.Admin.Core.RegisterModules;
  36. using System.IO;
  37. using Microsoft.OpenApi.Any;
  38. using Microsoft.AspNetCore.Mvc.Controllers;
  39. using ZhonTai.Admin.Core.Attributes;
  40. using ZhonTai.Admin.Core.Configs;
  41. using ZhonTai.Admin.Core.Consts;
  42. using MapsterMapper;
  43. using ZhonTai.DynamicApi;
  44. using NLog.Web;
  45. using Autofac.Extensions.DependencyInjection;
  46. using Microsoft.AspNetCore.Mvc;
  47. using ZhonTai.Admin.Core.Startup;
  48. using ZhonTai.Admin.Core.Conventions;
  49. using FreeSql;
  50. using ZhonTai.Admin.Services.User;
  51. using ZhonTai.Admin.Core.Middlewares;
  52. using ZhonTai.Admin.Core.Dto;
  53. using ZhonTai.DynamicApi.Attributes;
  54. using System.Text.RegularExpressions;
  55. using Swashbuckle.AspNetCore.SwaggerGen;
  56. using System.Text.Json.Serialization;
  57. namespace ZhonTai.Admin.Core;
  58. /// <summary>
  59. /// 宿主应用
  60. /// </summary>
  61. public class HostApp
  62. {
  63. readonly HostAppOptions _hostAppOptions;
  64. public HostApp()
  65. {
  66. }
  67. public HostApp(HostAppOptions hostAppOptions)
  68. {
  69. _hostAppOptions = hostAppOptions;
  70. }
  71. /// <summary>
  72. /// 运行应用
  73. /// </summary>
  74. /// <param name="args"></param>
  75. public void Run(string[] args)
  76. {
  77. var builder = WebApplication.CreateBuilder(args);
  78. //使用NLog日志
  79. builder.Host.UseNLog();
  80. var services = builder.Services;
  81. var env = builder.Environment;
  82. var configuration = builder.Configuration;
  83. var configHelper = new ConfigHelper();
  84. var appConfig = ConfigHelper.Get<AppConfig>("appconfig", env.EnvironmentName) ?? new AppConfig();
  85. //添加配置
  86. builder.Configuration.AddJsonFile("./Configs/ratelimitconfig.json", optional: true, reloadOnChange: true);
  87. if (env.EnvironmentName.NotNull())
  88. {
  89. builder.Configuration.AddJsonFile($"./Configs/ratelimitconfig.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
  90. }
  91. builder.Configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
  92. if (env.EnvironmentName.NotNull())
  93. {
  94. builder.Configuration.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);
  95. }
  96. var oSSConfigRoot = ConfigHelper.Load("ossconfig", env.EnvironmentName, true);
  97. services.Configure<OSSConfig>(oSSConfigRoot);
  98. //应用配置
  99. services.AddSingleton(appConfig);
  100. //使用Autofac容器
  101. builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
  102. //配置Autofac容器
  103. builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
  104. {
  105. // 控制器注入
  106. builder.RegisterModule(new ControllerModule());
  107. // 单例注入
  108. builder.RegisterModule(new SingleInstanceModule(appConfig));
  109. // 模块注入
  110. builder.RegisterModule(new RegisterModule(appConfig));
  111. });
  112. //配置Kestrel服务器
  113. builder.WebHost.ConfigureKestrel((context, options) =>
  114. {
  115. //设置应用服务器Kestrel请求体最大为100MB
  116. options.Limits.MaxRequestBodySize = appConfig.MaxRequestBodySize;
  117. });
  118. //访问地址
  119. builder.WebHost.UseUrls(appConfig.Urls);
  120. //配置服务
  121. ConfigureServices(services, env, configuration, configHelper, appConfig);
  122. var app = builder.Build();
  123. //配置中间件
  124. ConfigureMiddleware(app, env, configuration, appConfig);
  125. app.Run();
  126. }
  127. /// <summary>
  128. /// 实体类型重命名
  129. /// </summary>
  130. /// <param name="modelType"></param>
  131. /// <returns></returns>
  132. private string DefaultSchemaIdSelector(Type modelType)
  133. {
  134. if (!modelType.IsConstructedGenericType) return modelType.Name.Replace("[]", "Array");
  135. var prefix = modelType.GetGenericArguments()
  136. .Select(DefaultSchemaIdSelector)
  137. .Aggregate((previous, current) => previous + current);
  138. return modelType.Name.Split('`').First() + prefix;
  139. }
  140. /// <summary>
  141. /// 配置服务
  142. /// </summary>
  143. /// <param name="services"></param>
  144. /// <param name="env"></param>
  145. /// <param name="configuration"></param>
  146. /// <param name="configHelper"></param>
  147. /// <param name="appConfig"></param>
  148. private void ConfigureServices(IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration, ConfigHelper configHelper, AppConfig appConfig)
  149. {
  150. var hostAppContext = new HostAppContext()
  151. {
  152. Services = services,
  153. Environment = env,
  154. Configuration = configuration
  155. };
  156. _hostAppOptions?.ConfigurePreServices?.Invoke(hostAppContext);
  157. //雪花漂移算法
  158. var idGeneratorOptions = new IdGeneratorOptions(1) { WorkerIdBitLength = 6 };
  159. _hostAppOptions?.ConfigureIdGenerator?.Invoke(idGeneratorOptions);
  160. YitIdHelper.SetIdGenerator(idGeneratorOptions);
  161. //权限处理
  162. services.AddScoped<IPermissionHandler, PermissionHandler>();
  163. // ClaimType不被更改
  164. JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
  165. //用户信息
  166. services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  167. services.TryAddScoped<IUser, User>();
  168. //数据库配置
  169. var dbConfig = ConfigHelper.Get<DbConfig>("dbconfig", env.EnvironmentName);
  170. services.AddSingleton(dbConfig);
  171. //添加数据库
  172. if (!_hostAppOptions.CustomInitDb)
  173. {
  174. services.AddDb(env, _hostAppOptions);
  175. }
  176. //上传配置
  177. var uploadConfig = ConfigHelper.Load("uploadconfig", env.EnvironmentName, true);
  178. services.Configure<UploadConfig>(uploadConfig);
  179. //程序集
  180. Assembly[] assemblies = null;
  181. if(appConfig.AssemblyNames?.Length > 0)
  182. {
  183. assemblies = DependencyContext.Default.RuntimeLibraries
  184. .Where(a => appConfig.AssemblyNames.Contains(a.Name))
  185. .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
  186. }
  187. #region Mapster 映射配置
  188. services.AddScoped<IMapper>(sp => new Mapper());
  189. if(assemblies?.Length > 0)
  190. {
  191. TypeAdapterConfig.GlobalSettings.Scan(assemblies);
  192. }
  193. #endregion Mapster 映射配置
  194. #region Cors 跨域
  195. services.AddCors(options =>
  196. {
  197. options.AddPolicy(AdminConsts.RequestPolicyName, policy =>
  198. {
  199. var hasOrigins = appConfig.CorUrls?.Length > 0;
  200. if (hasOrigins)
  201. {
  202. policy.WithOrigins(appConfig.CorUrls);
  203. }
  204. else
  205. {
  206. policy.AllowAnyOrigin();
  207. }
  208. policy
  209. .AllowAnyHeader()
  210. .AllowAnyMethod();
  211. if (hasOrigins)
  212. {
  213. policy.AllowCredentials();
  214. }
  215. });
  216. //允许任何源访问Api策略,使用时在控制器或者接口上增加特性[EnableCors(AdminConsts.AllowAnyPolicyName)]
  217. options.AddPolicy(AdminConsts.AllowAnyPolicyName, policy =>
  218. {
  219. policy
  220. .AllowAnyOrigin()
  221. .AllowAnyHeader()
  222. .AllowAnyMethod();
  223. });
  224. });
  225. #endregion Cors 跨域
  226. #region 身份认证授权
  227. var jwtConfig = ConfigHelper.Get<JwtConfig>("jwtconfig", env.EnvironmentName);
  228. services.TryAddSingleton(jwtConfig);
  229. services.AddAuthentication(options =>
  230. {
  231. options.DefaultScheme = appConfig.IdentityServer.Enable ? IdentityServerAuthenticationDefaults.AuthenticationScheme : JwtBearerDefaults.AuthenticationScheme;
  232. options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401
  233. options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler); //403
  234. })
  235. .AddJwtBearer(options =>
  236. {
  237. //ids4
  238. if (appConfig.IdentityServer.Enable)
  239. {
  240. options.Authority = appConfig.IdentityServer.Url;
  241. options.RequireHttpsMetadata = appConfig.IdentityServer.RequireHttpsMetadata;
  242. options.Audience = appConfig.IdentityServer.Audience;
  243. }
  244. else
  245. {
  246. options.TokenValidationParameters = new TokenValidationParameters
  247. {
  248. ValidateIssuer = true,
  249. ValidateAudience = true,
  250. ValidateLifetime = true,
  251. ValidateIssuerSigningKey = true,
  252. ValidIssuer = jwtConfig.Issuer,
  253. ValidAudience = jwtConfig.Audience,
  254. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecurityKey)),
  255. ClockSkew = TimeSpan.Zero
  256. };
  257. }
  258. })
  259. .AddScheme<AuthenticationSchemeOptions, ResponseAuthenticationHandler>(nameof(ResponseAuthenticationHandler), o => { });
  260. #endregion 身份认证授权
  261. #region Swagger Api文档
  262. if (env.IsDevelopment() || appConfig.Swagger.Enable)
  263. {
  264. services.AddSwaggerGen(options =>
  265. {
  266. appConfig.Swagger.Projects?.ForEach(project =>
  267. {
  268. options.SwaggerDoc(project.Code.ToLower(), new OpenApiInfo
  269. {
  270. Title = project.Name,
  271. Version = project.Version,
  272. Description = project.Description
  273. });
  274. });
  275. options.CustomOperationIds(apiDesc =>
  276. {
  277. var controllerAction = apiDesc.ActionDescriptor as ControllerActionDescriptor;
  278. var api = controllerAction.AttributeRouteInfo.Template;
  279. api = Regex.Replace(api, @"[\{\\\/\}]", "-") + "-" + apiDesc.HttpMethod.ToLower();
  280. return api.Replace("--", "-");
  281. });
  282. options.ResolveConflictingActions(apiDescription => apiDescription.First());
  283. options.CustomSchemaIds(modelType => DefaultSchemaIdSelector(modelType));
  284. //支持多分组
  285. options.DocInclusionPredicate((docName, apiDescription) =>
  286. {
  287. var nonGroup = false;
  288. var groupNames = new List<string>();
  289. var dynamicApiAttribute = apiDescription.ActionDescriptor.EndpointMetadata.FirstOrDefault(x => x is DynamicApiAttribute);
  290. if (dynamicApiAttribute != null)
  291. {
  292. var dynamicApi = dynamicApiAttribute as DynamicApiAttribute;
  293. if(dynamicApi.GroupNames?.Length > 0)
  294. {
  295. groupNames.AddRange(dynamicApi.GroupNames);
  296. }
  297. }
  298. var apiGroupAttribute = apiDescription.ActionDescriptor.EndpointMetadata.FirstOrDefault(x => x is ApiGroupAttribute);
  299. if (apiGroupAttribute != null)
  300. {
  301. var apiGroup = apiGroupAttribute as ApiGroupAttribute;
  302. if (apiGroup.GroupNames?.Length > 0)
  303. {
  304. groupNames.AddRange(apiGroup.GroupNames);
  305. }
  306. nonGroup = apiGroup.NonGroup;
  307. }
  308. return docName == apiDescription.GroupName || groupNames.Any(a => a == docName) || nonGroup;
  309. });
  310. string[] xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "*.xml");
  311. if (xmlFiles.Length > 0)
  312. {
  313. foreach (var xmlFile in xmlFiles)
  314. {
  315. options.IncludeXmlComments(xmlFile, true);
  316. }
  317. }
  318. var server = new OpenApiServer()
  319. {
  320. Url = appConfig.Swagger.Url,
  321. Description = ""
  322. };
  323. if (appConfig.ApiUI.Footer.Enable)
  324. {
  325. server.Extensions.Add("extensions", new OpenApiObject
  326. {
  327. ["copyright"] = new OpenApiString(appConfig.ApiUI.Footer.Content)
  328. });
  329. }
  330. options.AddServer(server);
  331. if(appConfig.Swagger.EnableEnumSchemaFilter)
  332. {
  333. options.SchemaFilter<EnumSchemaFilter>();
  334. }
  335. if(appConfig.Swagger.EnableOrderTagsDocumentFilter)
  336. {
  337. options.DocumentFilter<OrderTagsDocumentFilter>();
  338. }
  339. options.OrderActionsBy(apiDesc =>
  340. {
  341. var order = 0;
  342. var objOrderAttribute = apiDesc.CustomAttributes().FirstOrDefault(x => x is OrderAttribute);
  343. if (objOrderAttribute != null)
  344. {
  345. var orderAttribute = objOrderAttribute as OrderAttribute;
  346. order = orderAttribute.Value;
  347. }
  348. return (int.MaxValue - order).ToString().PadLeft(int.MaxValue.ToString().Length, '0');
  349. });
  350. #region 添加设置Token的按钮
  351. if (appConfig.IdentityServer.Enable)
  352. {
  353. //添加Jwt验证设置
  354. options.AddSecurityRequirement(new OpenApiSecurityRequirement()
  355. {
  356. {
  357. new OpenApiSecurityScheme
  358. {
  359. Reference = new OpenApiReference
  360. {
  361. Id = "oauth2",
  362. Type = ReferenceType.SecurityScheme
  363. }
  364. },
  365. new List<string>()
  366. }
  367. });
  368. //统一认证
  369. options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
  370. {
  371. Type = SecuritySchemeType.OAuth2,
  372. Description = "oauth2登录授权",
  373. Flows = new OpenApiOAuthFlows
  374. {
  375. Implicit = new OpenApiOAuthFlow
  376. {
  377. AuthorizationUrl = new Uri($"{appConfig.IdentityServer.Url}/connect/authorize", UriKind.Absolute),
  378. TokenUrl = new Uri($"{appConfig.IdentityServer.Url}/connect/token", UriKind.Absolute),
  379. Scopes = new Dictionary<string, string>
  380. {
  381. { "admin.server.api", "admin后端api" }
  382. }
  383. }
  384. }
  385. });
  386. }
  387. else
  388. {
  389. //添加Jwt验证设置
  390. options.AddSecurityRequirement(new OpenApiSecurityRequirement()
  391. {
  392. {
  393. new OpenApiSecurityScheme
  394. {
  395. Reference = new OpenApiReference
  396. {
  397. Id = "Bearer",
  398. Type = ReferenceType.SecurityScheme
  399. }
  400. },
  401. new List<string>()
  402. }
  403. });
  404. options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
  405. {
  406. Description = "Value: Bearer {token}",
  407. Name = "Authorization",
  408. In = ParameterLocation.Header,
  409. Type = SecuritySchemeType.ApiKey
  410. });
  411. }
  412. #endregion 添加设置Token的按钮
  413. });
  414. }
  415. #endregion Swagger Api文档
  416. #region 操作日志
  417. if (appConfig.Log.Operation)
  418. {
  419. services.AddScoped<ILogHandler, LogHandler>();
  420. }
  421. #endregion 操作日志
  422. #region 控制器
  423. void mvcConfigure(MvcOptions options)
  424. {
  425. //options.Filters.Add<ControllerExceptionFilter>();
  426. options.Filters.Add<ValidateInputFilter>();
  427. if (appConfig.Validate.Login || appConfig.Validate.Permission)
  428. {
  429. options.Filters.Add<ValidatePermissionAttribute>();
  430. }
  431. //在具有较高的 Order 值的筛选器之前运行 before 代码
  432. //在具有较高的 Order 值的筛选器之后运行 after 代码
  433. if (appConfig.DynamicApi.FormatResult)
  434. {
  435. options.Filters.Add<FormatResultFilter>(20);
  436. }
  437. if (appConfig.Log.Operation)
  438. {
  439. options.Filters.Add<ControllerLogFilter>(10);
  440. }
  441. //禁止去除ActionAsync后缀
  442. //options.SuppressAsyncSuffixInActionNames = false;
  443. if (env.IsDevelopment() || appConfig.Swagger.Enable)
  444. {
  445. //API分组约定
  446. options.Conventions.Add(new ApiGroupConvention());
  447. }
  448. }
  449. var mvcBuilder = appConfig.AppType switch
  450. {
  451. AppType.Controllers => services.AddControllers(mvcConfigure),
  452. AppType.ControllersWithViews => services.AddControllersWithViews(mvcConfigure),
  453. AppType.MVC => services.AddMvc(mvcConfigure),
  454. _ => services.AddControllers(mvcConfigure)
  455. };
  456. if (assemblies?.Length > 0)
  457. {
  458. foreach (var assembly in assemblies)
  459. {
  460. services.AddValidatorsFromAssembly(assembly);
  461. }
  462. }
  463. services.AddFluentValidationAutoValidation();
  464. mvcBuilder.AddNewtonsoftJson(options =>
  465. {
  466. //忽略循环引用
  467. options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
  468. //使用驼峰 首字母小写
  469. options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  470. //设置时间格式
  471. options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
  472. })
  473. .AddControllersAsServices();
  474. if (appConfig.Swagger.EnableJsonStringEnumConverter)
  475. mvcBuilder.AddJsonOptions(options => options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()));
  476. _hostAppOptions?.ConfigureMvcBuilder?.Invoke(mvcBuilder, hostAppContext);
  477. #endregion 控制器
  478. services.AddHttpClient();
  479. _hostAppOptions?.ConfigureServices?.Invoke(hostAppContext);
  480. #region 缓存
  481. var cacheConfig = ConfigHelper.Get<CacheConfig>("cacheconfig", env.EnvironmentName);
  482. if (cacheConfig.Type == CacheType.Redis)
  483. {
  484. var csredis = new CSRedis.CSRedisClient(cacheConfig.Redis.ConnectionString);
  485. RedisHelper.Initialization(csredis);
  486. services.AddSingleton<ICacheTool, RedisCacheTool>();
  487. }
  488. else
  489. {
  490. services.AddMemoryCache();
  491. services.AddSingleton<ICacheTool, MemoryCacheTool>();
  492. }
  493. #endregion 缓存
  494. #region IP限流
  495. if (appConfig.RateLimit)
  496. {
  497. services.AddIpRateLimit(configuration, cacheConfig);
  498. }
  499. #endregion IP限流
  500. //阻止NLog接收状态消息
  501. services.Configure<ConsoleLifetimeOptions>(opts => opts.SuppressStatusMessages = true);
  502. //性能分析
  503. if (appConfig.MiniProfiler)
  504. {
  505. services.AddMiniProfiler();
  506. }
  507. //动态api
  508. services.AddDynamicApi(options =>
  509. {
  510. Assembly[] assemblies = DependencyContext.Default.RuntimeLibraries
  511. .Where(a => a.Name.EndsWith("Service"))
  512. .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
  513. options.AddAssemblyOptions(assemblies);
  514. options.FormatResult = appConfig.DynamicApi.FormatResult;
  515. options.FormatResultType = typeof(ResultOutput<>);
  516. _hostAppOptions?.ConfigureDynamicApi?.Invoke(options);
  517. });
  518. _hostAppOptions?.ConfigurePostServices?.Invoke(hostAppContext);
  519. }
  520. /// <summary>
  521. /// 配置中间件
  522. /// </summary>
  523. /// <param name="app"></param>
  524. /// <param name="env"></param>
  525. /// <param name="configuration"></param>
  526. /// <param name="appConfig"></param>
  527. private void ConfigureMiddleware(WebApplication app, IWebHostEnvironment env, IConfiguration configuration, AppConfig appConfig)
  528. {
  529. var hostAppMiddlewareContext = new HostAppMiddlewareContext()
  530. {
  531. App = app,
  532. Environment = env,
  533. Configuration = configuration
  534. };
  535. _hostAppOptions?.ConfigurePreMiddleware?.Invoke(hostAppMiddlewareContext);
  536. //异常处理
  537. app.UseMiddleware<ExceptionMiddleware>();
  538. //IP限流
  539. if (appConfig.RateLimit)
  540. {
  541. app.UseIpRateLimiting();
  542. }
  543. //性能分析
  544. if (appConfig.MiniProfiler)
  545. {
  546. app.UseMiniProfiler();
  547. }
  548. //静态文件
  549. app.UseDefaultFiles();
  550. app.UseStaticFiles();
  551. app.UseUploadConfig();
  552. //路由
  553. app.UseRouting();
  554. //跨域
  555. app.UseCors(AdminConsts.RequestPolicyName);
  556. //认证
  557. app.UseAuthentication();
  558. //授权
  559. app.UseAuthorization();
  560. //登录用户初始化数据权限
  561. if (appConfig.Validate.Permission)
  562. {
  563. app.Use(async (ctx, next) =>
  564. {
  565. var user = ctx.RequestServices.GetRequiredService<IUser>();
  566. if (user?.Id > 0)
  567. {
  568. var userService = ctx.RequestServices.GetRequiredService<IUserService>();
  569. await userService.GetDataPermissionAsync();
  570. }
  571. await next();
  572. });
  573. }
  574. //配置端点
  575. app.MapControllers();
  576. _hostAppOptions?.ConfigureMiddleware?.Invoke(hostAppMiddlewareContext);
  577. #region Swagger Api文档
  578. if (env.IsDevelopment() || appConfig.Swagger.Enable)
  579. {
  580. var routePrefix = appConfig.ApiUI.RoutePrefix;
  581. if (!appConfig.ApiUI.Enable && routePrefix.IsNull())
  582. {
  583. routePrefix = appConfig.Swagger.RoutePrefix;
  584. }
  585. var routePath = routePrefix.NotNull() ? $"{routePrefix}/" : "";
  586. app.UseSwagger(optoins =>
  587. {
  588. optoins.RouteTemplate = routePath + optoins.RouteTemplate;
  589. });
  590. app.UseSwaggerUI(options =>
  591. {
  592. options.RoutePrefix = appConfig.Swagger.RoutePrefix;
  593. appConfig.Swagger.Projects?.ForEach(project =>
  594. {
  595. options.SwaggerEndpoint($"/{routePath}swagger/{project.Code.ToLower()}/swagger.json", project.Name);
  596. });
  597. options.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None);//折叠Api
  598. //options.DefaultModelsExpandDepth(-1);//不显示Models
  599. if (appConfig.MiniProfiler)
  600. {
  601. options.InjectJavascript("/swagger/mini-profiler.js?v=4.2.22+2.0");
  602. options.InjectStylesheet("/swagger/mini-profiler.css?v=4.2.22+2.0");
  603. }
  604. });
  605. }
  606. #endregion Swagger Api文档
  607. _hostAppOptions?.ConfigurePostMiddleware?.Invoke(hostAppMiddlewareContext);
  608. }
  609. }