BaseStartup.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  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.Plate.Admin.HttpApi.Shared.Auth;
  29. using ZhonTai.Common.Auth;
  30. using ZhonTai.Common.Cache;
  31. using ZhonTai.Common.Configs;
  32. using ZhonTai.Common.Consts;
  33. using ZhonTai.Common.Helpers;
  34. using ZhonTai.Plate.Admin.HttpApi.Shared.Db;
  35. using ZhonTai.Plate.Admin.HttpApi.Shared.Enums;
  36. using ZhonTai.Plate.Admin.HttpApi.Shared.Extensions;
  37. using ZhonTai.Plate.Admin.HttpApi.Shared.Filters;
  38. using ZhonTai.Plate.Admin.HttpApi.Shared.Logs;
  39. using ZhonTai.Plate.Admin.HttpApi.Shared.RegisterModules;
  40. using MapsterMapper;
  41. namespace ZhonTai.Plate.Admin.HttpApi.Shared
  42. {
  43. public abstract class BaseStartup
  44. {
  45. private static string basePath => AppContext.BaseDirectory;
  46. private readonly IConfiguration _configuration;
  47. private readonly IHostEnvironment _env;
  48. private readonly ConfigHelper _configHelper;
  49. private readonly AppConfig _appConfig;
  50. private const string DefaultCorsPolicyName = "AllowPolicy";
  51. public BaseStartup(IConfiguration configuration, IWebHostEnvironment env)
  52. {
  53. _configuration = configuration;
  54. _env = env;
  55. _configHelper = new ConfigHelper();
  56. _appConfig = _configHelper.Get<AppConfig>("appconfig", env.EnvironmentName) ?? new AppConfig();
  57. }
  58. public virtual void ConfigureServices(IServiceCollection services)
  59. {
  60. //雪花漂移算法
  61. YitIdHelper.SetIdGenerator(new IdGeneratorOptions(1) { WorkerIdBitLength = 6 });
  62. //权限处理
  63. services.AddScoped<IPermissionHandler, PermissionHandler>();
  64. // ClaimType不被更改
  65. JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
  66. //用户信息
  67. services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  68. if (_appConfig.IdentityServer.Enable)
  69. {
  70. //is4
  71. services.TryAddSingleton<IUser, UserIdentiyServer>();
  72. }
  73. else
  74. {
  75. //jwt
  76. services.TryAddSingleton<IUser, User>();
  77. }
  78. //添加数据库
  79. services.AddDbAsync(_env).Wait();
  80. //添加IdleBus单例
  81. var dbConfig = new ConfigHelper().Get<DbConfig>("dbconfig", _env.EnvironmentName);
  82. var timeSpan = dbConfig.IdleTime > 0 ? TimeSpan.FromMinutes(dbConfig.IdleTime) : TimeSpan.MaxValue;
  83. IdleBus<IFreeSql> ib = new IdleBus<IFreeSql>(timeSpan);
  84. services.AddSingleton(ib);
  85. //数据库配置
  86. services.AddSingleton(dbConfig);
  87. //应用配置
  88. services.AddSingleton(_appConfig);
  89. //上传配置
  90. var uploadConfig = _configHelper.Load("uploadconfig", _env.EnvironmentName, true);
  91. services.Configure<UploadConfig>(uploadConfig);
  92. #region Mapster 映射配置
  93. Assembly[] assemblies = DependencyContext.Default.RuntimeLibraries
  94. .Where(a => a.Name.StartsWith("ZhonTai"))
  95. .Select(o => Assembly.Load(new AssemblyName(o.Name))).ToArray();
  96. services.AddScoped<IMapper>(sp => new Mapper());
  97. TypeAdapterConfig.GlobalSettings.Scan(assemblies);
  98. #endregion Mapster 映射配置
  99. #region Cors 跨域
  100. services.AddCors(options =>
  101. {
  102. options.AddPolicy(DefaultCorsPolicyName, policy =>
  103. {
  104. var hasOrigins = _appConfig.CorUrls?.Length > 0;
  105. if (hasOrigins)
  106. {
  107. policy.WithOrigins(_appConfig.CorUrls);
  108. }
  109. else
  110. {
  111. policy.AllowAnyOrigin();
  112. }
  113. policy
  114. .AllowAnyHeader()
  115. .AllowAnyMethod();
  116. if (hasOrigins)
  117. {
  118. policy.AllowCredentials();
  119. }
  120. });
  121. //允许任何源访问Api策略,使用时在控制器或者接口上增加特性[EnableCors(AdminConsts.AllowAnyPolicyName)]
  122. options.AddPolicy(AdminConsts.AllowAnyPolicyName, policy =>
  123. {
  124. policy
  125. .AllowAnyOrigin()
  126. .AllowAnyHeader()
  127. .AllowAnyMethod();
  128. });
  129. /*
  130. //浏览器会发起2次请求,使用OPTIONS发起预检请求,第二次才是api异步请求
  131. options.AddPolicy("All", policy =>
  132. {
  133. policy
  134. .AllowAnyOrigin()
  135. .SetPreflightMaxAge(new TimeSpan(0, 10, 0))
  136. .AllowAnyHeader()
  137. .AllowAnyMethod();
  138. });
  139. */
  140. });
  141. #endregion Cors 跨域
  142. #region 身份认证授权
  143. var jwtConfig = _configHelper.Get<JwtConfig>("jwtconfig", _env.EnvironmentName);
  144. services.TryAddSingleton(jwtConfig);
  145. if (_appConfig.IdentityServer.Enable)
  146. {
  147. //is4
  148. services.AddAuthentication(options =>
  149. {
  150. options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme;
  151. options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401
  152. options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler); //403
  153. })
  154. .AddJwtBearer(options =>
  155. {
  156. options.Authority = _appConfig.IdentityServer.Url;
  157. options.RequireHttpsMetadata = false;
  158. options.Audience = "admin.server.api";
  159. })
  160. .AddScheme<AuthenticationSchemeOptions, ResponseAuthenticationHandler>(nameof(ResponseAuthenticationHandler), o => { });
  161. }
  162. else
  163. {
  164. //jwt
  165. services.AddAuthentication(options =>
  166. {
  167. options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
  168. options.DefaultChallengeScheme = nameof(ResponseAuthenticationHandler); //401
  169. options.DefaultForbidScheme = nameof(ResponseAuthenticationHandler); //403
  170. })
  171. .AddJwtBearer(options =>
  172. {
  173. options.TokenValidationParameters = new TokenValidationParameters
  174. {
  175. ValidateIssuer = true,
  176. ValidateAudience = true,
  177. ValidateLifetime = true,
  178. ValidateIssuerSigningKey = true,
  179. ValidIssuer = jwtConfig.Issuer,
  180. ValidAudience = jwtConfig.Audience,
  181. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecurityKey)),
  182. ClockSkew = TimeSpan.Zero
  183. };
  184. })
  185. .AddScheme<AuthenticationSchemeOptions, ResponseAuthenticationHandler>(nameof(ResponseAuthenticationHandler), o => { });
  186. }
  187. #endregion 身份认证授权
  188. #region Swagger Api文档
  189. if (_env.IsDevelopment() || _appConfig.Swagger)
  190. {
  191. services.AddSwaggerGen(options =>
  192. {
  193. typeof(ApiVersion).GetEnumNames().ToList().ForEach(version =>
  194. {
  195. options.SwaggerDoc(version, new OpenApiInfo
  196. {
  197. Version = version,
  198. Title = "ZhonTai.Plate.Admin.Host"
  199. });
  200. //c.OrderActionsBy(o => o.RelativePath);
  201. });
  202. options.ResolveConflictingActions(apiDescription => apiDescription.First());
  203. options.CustomSchemaIds(x => x.FullName);
  204. //var xmlPath = Path.Combine(basePath, "ZhonTai.Plate.Admin.Host.xml");
  205. //options.IncludeXmlComments(xmlPath, true);
  206. //var xmlCommonPath = Path.Combine(basePath, "ZhonTai.Common.xml");
  207. //options.IncludeXmlComments(xmlCommonPath, true);
  208. //var xmlModelPath = Path.Combine(basePath, "ZhonTai.Plate.Admin.Domain.xml");
  209. //options.IncludeXmlComments(xmlModelPath);
  210. //var xmlServicesPath = Path.Combine(basePath, "ZhonTai.Plate.Admin.Service.xml");
  211. //options.IncludeXmlComments(xmlServicesPath);
  212. #region 添加设置Token的按钮
  213. if (_appConfig.IdentityServer.Enable)
  214. {
  215. //添加Jwt验证设置
  216. options.AddSecurityRequirement(new OpenApiSecurityRequirement()
  217. {
  218. {
  219. new OpenApiSecurityScheme
  220. {
  221. Reference = new OpenApiReference
  222. {
  223. Id = "oauth2",
  224. Type = ReferenceType.SecurityScheme
  225. }
  226. },
  227. new List<string>()
  228. }
  229. });
  230. //统一认证
  231. options.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
  232. {
  233. Type = SecuritySchemeType.OAuth2,
  234. Description = "oauth2登录授权",
  235. Flows = new OpenApiOAuthFlows
  236. {
  237. Implicit = new OpenApiOAuthFlow
  238. {
  239. AuthorizationUrl = new Uri($"{_appConfig.IdentityServer.Url}/connect/authorize"),
  240. Scopes = new Dictionary<string, string>
  241. {
  242. { "admin.server.api", "admin后端api" }
  243. }
  244. }
  245. }
  246. });
  247. }
  248. else
  249. {
  250. //添加Jwt验证设置
  251. options.AddSecurityRequirement(new OpenApiSecurityRequirement()
  252. {
  253. {
  254. new OpenApiSecurityScheme
  255. {
  256. Reference = new OpenApiReference
  257. {
  258. Id = "Bearer",
  259. Type = ReferenceType.SecurityScheme
  260. }
  261. },
  262. new List<string>()
  263. }
  264. });
  265. options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
  266. {
  267. Description = "Value: Bearer {token}",
  268. Name = "Authorization",
  269. In = ParameterLocation.Header,
  270. Type = SecuritySchemeType.ApiKey
  271. });
  272. }
  273. #endregion 添加设置Token的按钮
  274. });
  275. }
  276. #endregion Swagger Api文档
  277. #region 操作日志
  278. if (_appConfig.Log.Operation)
  279. {
  280. services.AddScoped<ILogHandler, LogHandler>();
  281. }
  282. #endregion 操作日志
  283. #region 控制器
  284. services.AddControllers(options =>
  285. {
  286. options.Filters.Add<AdminExceptionFilter>();
  287. if (_appConfig.Log.Operation)
  288. {
  289. options.Filters.Add<LogActionFilter>();
  290. }
  291. //禁止去除ActionAsync后缀
  292. options.SuppressAsyncSuffixInActionNames = false;
  293. })
  294. //.AddFluentValidation(config =>
  295. //{
  296. // var assembly = Assembly.LoadFrom(Path.Combine(basePath, "ZhonTai.Plate.Admin.Host.dll"));
  297. // config.RegisterValidatorsFromAssembly(assembly);
  298. //})
  299. .AddNewtonsoftJson(options =>
  300. {
  301. //忽略循环引用
  302. options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
  303. //使用驼峰 首字母小写
  304. options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
  305. //设置时间格式
  306. options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
  307. })
  308. .AddControllersAsServices();
  309. #endregion 控制器
  310. #region 缓存
  311. var cacheConfig = _configHelper.Get<CacheConfig>("cacheconfig", _env.EnvironmentName);
  312. if (cacheConfig.Type == CacheType.Redis)
  313. {
  314. var csredis = new CSRedis.CSRedisClient(cacheConfig.Redis.ConnectionString);
  315. RedisHelper.Initialization(csredis);
  316. services.AddSingleton<ICache, RedisCache>();
  317. }
  318. else
  319. {
  320. services.AddMemoryCache();
  321. services.AddSingleton<ICache, MemoryCache>();
  322. }
  323. #endregion 缓存
  324. #region IP限流
  325. if (_appConfig.RateLimit)
  326. {
  327. services.AddIpRateLimit(_configuration, cacheConfig);
  328. }
  329. #endregion IP限流
  330. //阻止NLog接收状态消息
  331. services.Configure<ConsoleLifetimeOptions>(opts => opts.SuppressStatusMessages = true);
  332. }
  333. public virtual void ConfigureContainer(ContainerBuilder builder)
  334. {
  335. #region AutoFac IOC容器
  336. try
  337. {
  338. // 控制器注入
  339. builder.RegisterModule(new ControllerModule());
  340. // 单例注入
  341. builder.RegisterModule(new SingleInstanceModule());
  342. // 仓储注入
  343. builder.RegisterModule(new RepositoryModule());
  344. // 服务注入
  345. builder.RegisterModule(new ServiceModule(_appConfig));
  346. }
  347. catch (Exception ex)
  348. {
  349. throw new Exception(ex.Message + "\n" + ex.InnerException);
  350. }
  351. #endregion AutoFac IOC容器
  352. }
  353. public virtual void Configure(IApplicationBuilder app)
  354. {
  355. #region app配置
  356. //IP限流
  357. if (_appConfig.RateLimit)
  358. {
  359. app.UseIpRateLimiting();
  360. }
  361. //异常
  362. app.UseExceptionHandler("/Error");
  363. //静态文件
  364. app.UseUploadConfig();
  365. //路由
  366. app.UseRouting();
  367. //跨域
  368. app.UseCors(DefaultCorsPolicyName);
  369. //认证
  370. app.UseAuthentication();
  371. //授权
  372. app.UseAuthorization();
  373. //配置端点
  374. app.UseEndpoints(endpoints =>
  375. {
  376. endpoints.MapControllers();
  377. });
  378. #endregion app配置
  379. #region Swagger Api文档
  380. if (_env.IsDevelopment() || _appConfig.Swagger)
  381. {
  382. app.UseSwagger();
  383. app.UseSwaggerUI(c =>
  384. {
  385. typeof(ApiVersion).GetEnumNames().OrderByDescending(e => e).ToList().ForEach(version =>
  386. {
  387. c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"ZhonTai.Plate.Admin.Host {version}");
  388. });
  389. c.RoutePrefix = "";//直接根目录访问,如果是IIS发布可以注释该语句,并打开launchSettings.launchUrl
  390. c.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.None);//折叠Api
  391. //c.DefaultModelsExpandDepth(-1);//不显示Models
  392. });
  393. }
  394. #endregion Swagger Api文档
  395. //数据库日志
  396. //var log = LogManager.GetLogger("db");
  397. //var ei = new LogEventInfo(LogLevel.Error, "", "错误信息");
  398. //ei.Properties["id"] = YitIdHelper.NextId();
  399. //log.Log(ei);
  400. }
  401. }
  402. }