using Hangfire.Redis.StackExchange; using JiShe.ServicePro.Core; using JiShe.ServicePro.FreeRedisProvider; using JiShe.ServicePro.SwaggerConfigs; using Medallion.Threading; using Medallion.Threading.Redis; using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.CodeAnalysis; using System.Reflection; using Volo.Abp.BlobStoring; using Volo.Abp.BlobStoring.FileSystem; namespace JiShe.IoT; public partial class IoTHttpApiHostModule { private void ConfigureHangfire(ServiceConfigurationContext context) { var redisStorageOptions = new RedisStorageOptions() { Db = context.Services.GetConfiguration().GetValue("Hangfire:Redis:DB") }; Configure(options => { options.IsJobExecutionEnabled = true; }); context.Services.AddHangfire(config => { config.UseRedisStorage( context.Services.GetConfiguration().GetValue("Hangfire:Redis:Host"), redisStorageOptions) .WithJobExpirationTimeout(TimeSpan.FromDays(7)); var delaysInSeconds = new[] { 10, 60, 60 * 3 }; // 重试时间间隔 const int Attempts = 3; // 重试次数 config.UseFilter(new AutomaticRetryAttribute() { Attempts = Attempts, DelaysInSeconds = delaysInSeconds }); //config.UseFilter(new AutoDeleteAfterSuccessAttribute(TimeSpan.FromDays(7))); config.UseFilter(new JobRetryLastFilter(Attempts)); }); } /// /// 配置MiniProfiler /// private void ConfigureMiniProfiler(ServiceConfigurationContext context) { if (context.Services.GetConfiguration().GetValue("MiniProfiler:Enabled", false)) { context.Services.AddMiniProfiler(options => options.RouteBasePath = "/profiler").AddEntityFramework(); } } /// /// 配置JWT /// private void ConfigureJwtAuthentication(ServiceConfigurationContext context, IConfiguration configuration) { context.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters() { // 是否开启签名认证 ValidateIssuerSigningKey = true, ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ClockSkew = TimeSpan.Zero, ValidIssuer = configuration["Jwt:Issuer"], ValidAudience = configuration["Jwt:Audience"], IssuerSigningKey = new SymmetricSecurityKey( Encoding.ASCII.GetBytes(configuration["Jwt:SecurityKey"])) }; options.Events = new JwtBearerEvents { OnMessageReceived = currentContext => { var path = currentContext.HttpContext.Request.Path; if (path.StartsWithSegments("/login")) { return Task.CompletedTask; } var accessToken = string.Empty; if (currentContext.HttpContext.Request.Headers.ContainsKey("Authorization")) { accessToken = currentContext.HttpContext.Request.Headers["Authorization"]; if (!string.IsNullOrWhiteSpace(accessToken)) { accessToken = accessToken.Split(" ").LastOrDefault(); } } if (accessToken.IsNullOrWhiteSpace()) { accessToken = currentContext.Request.Query["access_token"].FirstOrDefault(); } if (accessToken.IsNullOrWhiteSpace()) { accessToken = currentContext.Request.Cookies[IoTHttpApiHostConst.DefaultCookieName]; } currentContext.Token = accessToken; currentContext.Request.Headers.Remove("Authorization"); currentContext.Request.Headers.Append("Authorization", $"Bearer {accessToken}"); return Task.CompletedTask; } }; }); } /// /// Redis缓存 /// private void ConfigureCache(ServiceConfigurationContext context) { Configure( options => { options.KeyPrefix = "JiSheIoT:"; }); var configuration = context.Services.GetConfiguration(); context.Services .AddDataProtection() .PersistKeysToStackFreeRedis("JiSheIoTAdmin-Protection-Keys"); } /// /// 配置Identity /// private void ConfigureIdentity(ServiceConfigurationContext context) { context.Services.Configure(options => { options.Lockout = new LockoutOptions() { AllowedForNewUsers = false }; }); } private void ConfigurationSignalR(ServiceConfigurationContext context) { context.Services .AddSignalR() .AddStackExchangeRedis(context.Services.GetConfiguration().GetValue("Redis:Configuration"), options => { options.Configuration.ChannelPrefix = "JiShe.ServicePro"; }); } private void ConfigureSwaggerServices(ServiceConfigurationContext context) { context.Services.AddSwaggerGen( options => { // 文件下载类型 options.MapType(() => new OpenApiSchema() { Type = "file" }); //options.SwaggerDoc("AbpPro", // new OpenApiInfo { Title = "AbpPro API", Version = "v1" }); var configuration = context.Services.GetConfiguration(); var groupNames = EnumExtensions.GetEnumTypeValueNameList(); var excludeSwaggerGroups = configuration.GetSection("ExcludeSwaggerGroup").Get>() ?? new List(); groupNames.ForEach(group => { if (!excludeSwaggerGroups.Where(e => e == group.Key).Any()) { options.SwaggerDoc(group.Key, new OpenApiInfo { Title = group.Value, Version = "v1" }); } }); options.DocInclusionPredicate((docName, description) => { return description.GroupName == docName; }); //options.EnableAnnotations(enableAnnotationsForInheritance: true, enableAnnotationsForPolymorphism: true); // 启用注解 options.DocumentFilter(); options.SchemaFilter(); // 加载所有xml注释,这里会导致swagger加载有点缓慢 var xmlPaths = Directory.GetFiles(AppContext.BaseDirectory, "*.xml"); foreach (var xml in xmlPaths) { options.IncludeXmlComments(xml, true); } // 加载 模块引入的xml注释 // 加载所有xml注释,这里会导致swagger加载有点缓慢 var modulePath = Path.Combine(AppContext.BaseDirectory, "moduleSwagger"); if (Directory.Exists(modulePath)) { var xmlModulePaths = Directory.GetFiles(modulePath, "*.xml"); foreach (var xml in xmlModulePaths) { options.IncludeXmlComments(xml, true); } } options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme() { Description = "直接在下框输入JWT生成的Token", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.Http, Scheme = JwtBearerDefaults.AuthenticationScheme, BearerFormat = "JWT" }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" } }, new List() } }); options.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme() { Type = SecuritySchemeType.ApiKey, In = ParameterLocation.Header, Name = "Accept-Language", Description = "多语言设置,系统预设语言有zh-Hans、en,默认为zh-Hans", }); options.AddSecurityRequirement(new OpenApiSecurityRequirement { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "ApiKey" } }, Array.Empty() } }); }); } private void ConfigureCap(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); context.AddAbpCap(capOptions => { capOptions.SetCapDbConnectionString(configuration["ConnectionStrings:Default"]); capOptions.UseEntityFramework(); capOptions.UseRabbitMQ(option => { option.HostName = configuration.GetValue("Cap:RabbitMq:HostName"); option.UserName = configuration.GetValue("Cap:RabbitMq:UserName"); option.Password = configuration.GetValue("Cap:RabbitMq:Password"); option.Port = configuration.GetValue("Cap:RabbitMq:Port"); }); capOptions.UseDashboard(options => { options.AuthorizationPolicy = ServiceProCapPermissions.CapManagement.Cap; }); }); } /// /// 审计日志 /// private void ConfigureAuditLog(ServiceConfigurationContext context) { Configure ( options => { options.IsEnabled = true; EntityHistorySelectorListExtensions.AddAllEntities(options.EntityHistorySelectors); options.ApplicationName = "JiShe.ServicePro"; } ); Configure( options => { options.IgnoredUrls.Add("/AuditLogs/page"); options.IgnoredUrls.Add("/hangfire/stats"); options.IgnoredUrls.Add("/hangfire/recurring/trigger"); options.IgnoredUrls.Add("/cap"); options.IgnoredUrls.Add("/"); }); } private void ConfigurationMultiTenancy() { Configure(options => { options.IsEnabled = MultiTenancyConsts.IsEnabled; }); } /// /// 配置redis分布式锁 /// private void ConfigurationDistributedLocking(ServiceConfigurationContext context) { var configuration = context.Services.GetConfiguration(); var connectionString = configuration.GetValue("Redis:Configuration"); context.Services.AddSingleton(sp => { var connection = ConnectionMultiplexer.Connect(connectionString); return new RedisDistributedSynchronizationProvider(connection.GetDatabase()); }); } /// /// 配置 文件管理的 blob设置,默认使用本地文件系统 /// private void ConfigureBlobStorage() { Configure(options => { options.Containers.ConfigureDefault(container => { container.UseFileSystem(fileSystem => { string[] filePathArray = new string[] { Environment.CurrentDirectory, "UploadFile", DateTime.Now.Date.ToString("yyyyMMdd") }; string filePath = Path.Combine(filePathArray); //检查文件夹是否存在 if (!System.IO.Directory.Exists(filePath)) { System.IO.Directory.CreateDirectory(filePath); } fileSystem.BasePath = filePath; }); }); }); } }