using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System.Reflection; using YD_WeChatApplet.Context; using Microsoft.EntityFrameworkCore; using YD_WeChatApplet.Services; using YD_WeChatApplet.Commons.Filters; using YD_WeChatApplet.Commons.Users; using Newtonsoft.Json.Serialization; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; using YD_WeChatApplet.Commons.Utils; using YD_WeChatApplet.Api.Utilities; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc.Authorization; using YD_WeChatApplet.Extensions; using Autofac; using YD_WeChatApplet.Api.Services.Impl; using YD_WeChatApplet.Api.AutoMappers; using YD_WeChatApplet.Api.Filters; namespace YD_WeChatApplet { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } private IServiceCollection Services { get; set; } public void ConfigureServices(IServiceCollection services) { Services = services; AppSettings.Init(Configuration); string dbConnectionString = AppSettings.DbConnectionString; string smartSportsString = AppSettings.SmartSportsString; // 使用 dbConnectionString 配置数据库上下文 services.AddDbContextPool(optionsBuilder => { optionsBuilder.UseSqlServer(dbConnectionString); }); // 配置智慧体育后台数据库上下文 services.AddDbContextPool(optionsBuilder => { optionsBuilder.UseSqlServer(smartSportsString); }); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddSession(); services.AddMemoryCache(); services.AddHttpContextAccessor(); Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { SaveSigninToken = true,//保存token,后台验证token是否生效(重要) ValidateIssuer = true,//是否验证Issuer ValidateAudience = true,//是否验证Audience ValidateLifetime = true,//是否验证失效时间 ValidateIssuerSigningKey = true,//是否验证SecurityKey ValidAudience = AppSettings.Secret.Audience,//Audience ValidIssuer = AppSettings.Secret.Issuer,//Issuer,这两项和前面签发jwt的设置一致 IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(AppSettings.Secret.JWT)) }; options.Events = new JwtBearerEvents() { OnChallenge = context => { context.HandleResponse(); context.Response.Clear(); context.Response.ContentType = "application/json"; context.Response.StatusCode = 401; Task task = context.Response.WriteAsync(new { message = "授权未通过", status = false, code = 401 }.Serialize()); return Task.CompletedTask; } }; }); // 全局应用认证策略 services.AddControllers(options => { var policy = new AuthorizationPolicyBuilder() .RequireAuthenticatedUser() .Build(); options.Filters.Add(new AuthorizeFilter(policy)); // 全局应用 [Authorize] }); //必须appsettings.json中配置 string corsUrls = Configuration["CorsUrls"]; if (string.IsNullOrEmpty(corsUrls)) { throw new Exception("请配置跨请求的前端Url"); } services.AddCors(options => { options.AddDefaultPolicy( builder => { builder.AllowAnyOrigin() .SetPreflightMaxAge(TimeSpan.FromSeconds(2520)) .AllowAnyHeader().AllowAnyMethod(); }); }); services.AddSingleton(); services.AddControllers(options => { options.Filters.Add(); // 1、通用结果 options.Filters.Add();// 2、通用异常 options.Filters.Add(); options.ModelBinderProviders.Insert(0, new SysUserModelBinderProvider());// 3、自定义模型绑定 options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true; }).AddNewtonsoftJson(options => { // 防止将大写转换成小写 //options.SerializerSettings.ContractResolver = new DefaultContractResolver(); options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; }); services.AddSwaggerGen(c => { //分为2份接口文档 c.SwaggerDoc("v1", new OpenApiInfo { Title = "YD_WeChatApplet.Api", Version = "v1", Description = "跃动小程序Api" }); string xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; string xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath, true); c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "YD_WeChatApplet.Api.xml")); //c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "YD_WeChatApplet.Model.xml")); c.DocInclusionPredicate((docName, apiDes) => { if (!apiDes.TryGetMethodInfo(out MethodInfo method)) return false; /*使用ApiExplorerSettingsAttribute里面的GroupName进行特性标识 * DeclaringType只能获取controller上的特性 * 我们这里是想以action的特性为主 * */ var version = method.DeclaringType.GetCustomAttributes(true).OfType().Select(m => m.GroupName); if (docName == "v1" && !version.Any()) return true; //这里获取action的特性 var actionVersion = method.GetCustomAttributes(true).OfType().Select(m => m.GroupName); if (actionVersion.Any()) return actionVersion.Any(v => v == docName); return version.Any(v => v == docName); }); var security = new Dictionary> { { AppSettings.Secret.Issuer, new string[] { } } }; c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme() { Description = "JWT授权token前面需要加上字段Bearer与一个空格,如Bearer token", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey, BearerFormat = "JWT", Scheme = "Bearer" }); c.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new string[] { } } }); }) .AddControllers() .ConfigureApiBehaviorOptions(options => { options.SuppressConsumesConstraintForFormFileParameters = true; options.SuppressInferBindingSourcesForParameters = true; options.SuppressModelStateInvalidFilter = true; options.SuppressMapClientErrors = true; options.ClientErrorMapping[404].Link = "https://*/404"; }); services.AddSignalR(); services.AddHttpClient(); services.AddAutoMapper(typeof(MappingProfile)); //设置文件上传大小限制 //设置文件上传大小限制 services.Configure(x => { x.MultipartBodyLengthLimit = 1024 * 1024 * 100;//100M }); services.Configure(options => { options.Limits.MaxRequestBodySize = 1024 * 1024 * 100;//100M }); services.Configure(options => { options.MaxRequestBodySize = 1024 * 1024 * 100;//100M }); } public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterType().InstancePerLifetimeScope(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //else //{ // app.UseQuartz(env); //} //app.UseMiddleware(); app.UseStaticFiles().UseStaticFiles(new StaticFileOptions { ServeUnknownFileTypes = true }); app.UseDefaultFiles(); app.UseStaticFiles(); //app.Use(HttpRequestMiddleware.Context); //2021.06.27增加创建默认upload文件夹 //string _uploadPath = (env.ContentRootPath + "/Upload").ReplacePath(); //if (!Directory.Exists(_uploadPath)) //{ // Directory.CreateDirectory(_uploadPath); //} //app.UseStaticFiles(new StaticFileOptions() //{ // FileProvider = new PhysicalFileProvider( // Path.Combine(Directory.GetCurrentDirectory(), @"Upload")), // //配置访问虚拟目录时文件夹别名 // RequestPath = "/Upload", // OnPrepareResponse = (Microsoft.AspNetCore.StaticFiles.StaticFileResponseContext staticFile) => // { // //可以在此处读取请求的信息进行权限认证 // // staticFile.File // // staticFile.Context.Response.StatusCode; // } //}); //配置HttpContext app.UseStaticHttpContext(); app.UseSwagger(); app.UseSwaggerUI(c => { //2个下拉框选项 选择对应的文档 c.SwaggerEndpoint("/swagger/v1/swagger.json", "YD_WeChatApplet.Api"); c.RoutePrefix = ""; }); app.UseRouting(); app.UseCors(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); //配置SignalR //if (AppSetting.UseSignalR) //{ // string corsUrls = Configuration["CorsUrls"]; // endpoints.MapHub("/message") // .RequireCors(t => // t.WithOrigins(corsUrls.Split(',')). // AllowAnyMethod(). // AllowAnyHeader(). // AllowCredentials()); //} }); } } /// /// Swagger注释帮助类 /// public class SwaggerDocTag : IDocumentFilter { /// /// 添加附加注释 /// /// /// public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) { //添加对应的控制器描述 swaggerDoc.Tags = new List { new OpenApiTag { Name = "Test", Description = "这是描述" }, //new OpenApiTag { Name = "你的控制器名字,不带Controller", Description = "控制器描述" }, }; } } }