using System; using System.Collections.Generic; using System.IO; using System.Security.Claims; using System.Text; using System.Text.Encodings.Web; using System.Text.Unicode; using HaBookCms.AzureCosmos.ServiceExtension; using HaBookCms.AzureStorage.ServiceExtension; using HaBookCms.Common.LogHelper; using HaBookCms.ContextConfig.Attributes; using HaBookCms.ContextConfig.Exceptions; using HaBookCms.Jwt.Filter; using HaBookCms.Jwt.Model; using HaBookCms.RedisStorage.Cache; using HaBookCms.ServiceOptions.Options; using log4net; using log4net.Config; using log4net.Repository; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.SpaServices.Webpack; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; namespace HaBookCms.Contest { public class Startup { /// /// log4net 仓储库 /// public static ILoggerRepository repository { get; set; } public Startup(IConfiguration configuration, IHostingEnvironment env) { Configuration = configuration; var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true); this.Configuration = builder.Build(); //log4net repository = LogManager.CreateRepository("HaBookCms"); //指定配置文件 XmlConfigurator.Configure(repository, new FileInfo("Log4net.config")); BaseConfigModel.SetBaseConfig(Configuration, env.ContentRootPath, env.WebRootPath); } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) {//Configuration["AppSettings:Azure:TableStorageConnection"] services.AddAzureTableStorage().AddAzureBlobStorage().AddConnection(new AzureStorageOptions { ConnectionString = Configuration["AppSettings:Azure:StorageConnection"] }); services.Configure(options => { // This lambda determines whether user consent for non-essential cookies is needed for a given request. options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddAzureCosmosDB().AddCosmosDBConnection(new AzureCosmosDBOptions() { ConnectionString = Configuration["AppSettings:Azure:CosmosDBConnection:AccountEndpoint"], ConnectionKey= Configuration["AppSettings:Azure:CosmosDBConnection:AccountKey"], Database = Configuration["AppSettings:Azure:CosmosDBConnection:Database"], }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); //services.AddMvc().AddMvcOptions( // option => // { // option.OutputFormatters.Clear(); // option.OutputFormatters.Add(new MessagePackOutputFormatter(ContractlessStandardResolver.Instance)); // option.InputFormatters.Clear(); // option.InputFormatters.Add(new MessagePackInputFormatter(ContractlessStandardResolver.Instance)); // }); //解决视图输出内容中文编码问题 services.AddSingleton(HtmlEncoder.Create(UnicodeRanges.All)); services.AddSingleton(); #region 认证 JwtAuthConfigModel jwtConfig = new JwtAuthConfigModel(); // services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) //.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, o => // { // o.LoginPath = new PathString("/api/Users/checkLogin"); // }) services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, o => { o.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = jwtConfig.Issuer, ValidAudience = jwtConfig.Audience, IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig.JWTSecretKey)), /***********************************TokenValidationParameters的参数默认值***********************************/ RequireSignedTokens = true, // SaveSigninToken = false, // ValidateActor = false, // 将下面两个参数设置为false,可以不验证Issuer和Audience,但是不建议这样做。 ValidateAudience = true, ValidateIssuer = true, ValidateIssuerSigningKey = true, // 是否要求Token的Claims中必须包含 Expires RequireExpirationTime = true, // 允许的服务器时间偏移量 // ClockSkew = TimeSpan.FromSeconds(300), ClockSkew = TimeSpan.Zero, // 是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比 ValidateLifetime = true }; }); #endregion var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtConfig.JWTSecretKey)), SecurityAlgorithms.HmacSha256); // 如果要数据库动态绑定,这里先留个空,后边处理器里动态赋值 var permission = new List(); // 角色与接口的权限要求参数 var permissionRequirement = new PermissionRequirement( "/api/denied",// 拒绝授权的跳转地址(目前无用) permission, ClaimTypes.Role,//基于角色的授权 jwtConfig.Issuer,//发行人 jwtConfig.Audience,//听众 signingCredentials,//签名凭据 expiration: TimeSpan.FromSeconds(60 * 2)//接口的过期时间 ); // services.AddSingleton(); #region 授权 services.AddAuthorization(options => { options.AddPolicy("RequireContestWeb", policy => policy.RequireRole("ContestWeb").Build()); options.AddPolicy("RequireApp", policy => policy.RequireRole("App").Build()); options.AddPolicy("RequireAdmin", policy => policy.RequireRole("Admin").Build()); options.AddPolicy("RequireAdminOrApp", policy => policy.RequireRole("Admin,App").Build()); // 自定义权限要求 options.AddPolicy("Permission", policy => policy.Requirements.Add(permissionRequirement)); }); #endregion //log日志注入 services.AddSingleton(); #region 缓存 读取配置是否使用哪种缓存模式 services.AddMemoryCache(); if (Convert.ToBoolean(Configuration["Cache:IsUseRedis"])) { services.AddSingleton(); } else { services.AddSingleton(); } #endregion #region 缓存 RedisCache //将Redis分布式缓存服务添加到服务中 services.AddDistributedRedisCache(options => { //用于连接Redis的配置 options.Configuration = "localhost";// Configuration.GetConnectionString("RedisConnectionString"); //Redis实例名RedisDistributedCache options.InstanceName = "RedisInstance"; }); #endregion #region CORS services.AddCors(c => { c.AddPolicy("Any", policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials(); }); c.AddPolicy("Limit", policy => { policy .WithOrigins("localhost:63969") .WithMethods("get", "post", "put", "delete") //.WithHeaders("Authorization"); .AllowAnyHeader(); }); }); #endregion #region 性能 压缩 services.AddResponseCompression(); #endregion //跨域//设置了允许所有来源 services.AddCors(options => options.AddPolicy("any", builder => builder.AllowAnyMethod().AllowAnyHeader().AllowAnyOrigin().AllowCredentials())); services.AddMvc(options => { options.Filters.Add(new AllowCorsAttribute()); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); //app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions //{ // HotModuleReplacement = true //}); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } #region 解决Ubuntu Nginx 代理不能获取IP问题 app.UseForwardedHeaders(new ForwardedHeadersOptions { ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto }); #endregion app.UseHttpsRedirection(); app.UseStaticFiles(new StaticFileOptions { ServeUnknownFileTypes = true //ContentTypeProvider = new FileExtensionContentTypeProvider(new Dictionary //{ // { ".apk","application/vnd.android.package-archive"}, // { ".nupkg","application/zip"} //}) //支持特殊文件下载处理 }); //自定义异常处理 app.UseMiddleware(); //认证 app.UseAuthentication(); //授权 app.UseMiddleware(); //性能压缩 app.UseResponseCompression(); app.UseCookiePolicy(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } } }