From eb2c05e9dfe634eb947e3899f17554a9cc7522bc Mon Sep 17 00:00:00 2001 From: chenchun Date: Tue, 19 Nov 2024 16:36:33 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E6=88=90=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=A4=9Adb=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DbConnOptions.cs | 4 +- .../ISqlSugarDbConnectionCreator.cs | 24 - .../ISqlSugarDbContextDependencies.cs | 2 +- ...xtensions.cs => SqlSugarCoreExtensions.cs} | 23 +- .../SqlSugarDbContext.cs | 1 + .../SqlSugarDbContextFactory.cs | 80 ++-- .../YiFrameworkSqlSugarCoreModule.cs | 5 +- Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs | 430 +++++++++--------- 8 files changed, 284 insertions(+), 285 deletions(-) delete mode 100644 Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbConnectionCreator.cs rename Yi.Abp.Net8/framework/{Yi.Framework.SqlSugarCore => Yi.Framework.SqlSugarCore.Abstractions}/ISqlSugarDbContextDependencies.cs (92%) rename Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/{SqlsugarCoreExtensions.cs => SqlSugarCoreExtensions.cs} (55%) diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs index db6be5b3..6533950c 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/DbConnOptions.cs @@ -1,4 +1,5 @@ using SqlSugar; +using ArgumentException = System.ArgumentException; namespace Yi.Framework.SqlSugarCore.Abstractions { @@ -53,6 +54,5 @@ namespace Yi.Framework.SqlSugarCore.Abstractions /// 开启Saas多租户 /// public bool EnabledSaasMultiTenancy { get; set; } = false; - } -} +} \ No newline at end of file diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbConnectionCreator.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbConnectionCreator.cs deleted file mode 100644 index dc5c06f1..00000000 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbConnectionCreator.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using SqlSugar; - -namespace Yi.Framework.SqlSugarCore.Abstractions -{ - public interface ISqlSugarDbConnectionCreator - { - DbConnOptions Options { get; } - Action OnSqlSugarClientConfig { get; set; } - Action DataExecuted { get; set; } - Action DataExecuting { get; set; } - Action OnLogExecuting { get; set; } - Action OnLogExecuted { get; set; } - Action EntityService { get; set; } - - ConnectionConfig Build(Action? action = null); - void SetDbAop(ISqlSugarClient currentDb); - } -} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/ISqlSugarDbContextDependencies.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContextDependencies.cs similarity index 92% rename from Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/ISqlSugarDbContextDependencies.cs rename to Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContextDependencies.cs index 84f161d8..f41bb88d 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/ISqlSugarDbContextDependencies.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore.Abstractions/ISqlSugarDbContextDependencies.cs @@ -1,7 +1,7 @@ using System.Reflection; using SqlSugar; -namespace Yi.Framework.SqlSugarCore; +namespace Yi.Framework.SqlSugarCore.Abstractions; public interface ISqlSugarDbContextDependencies { diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlsugarCoreExtensions.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarCoreExtensions.cs similarity index 55% rename from Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlsugarCoreExtensions.cs rename to Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarCoreExtensions.cs index d8fa89fc..0c5057f8 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlsugarCoreExtensions.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarCoreExtensions.cs @@ -9,20 +9,31 @@ using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.SqlSugarCore { - public static class SqlsugarCoreExtensions + public static class SqlSugarCoreExtensions { + /// + /// 新增db对象,可支持多个 + /// + /// + /// + /// + /// public static IServiceCollection AddYiDbContext(this IServiceCollection service, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) where TDbContext : class, ISqlSugarDbContextDependencies { - service.Add(new ServiceDescriptor(typeof(ISqlSugarDbContextDependencies), typeof(TDbContext), serviceLifetime)); + service.AddTransient(); return service; } + /// + /// 新增db对象,可支持多个 + /// + /// + /// + /// + /// public static IServiceCollection AddYiDbContext(this IServiceCollection service, Action options) where TDbContext : class, ISqlSugarDbContextDependencies { - service.Configure(ops => - { - options.Invoke(ops); - }); + service.Configure(options.Invoke); service.AddYiDbContext(); return service; } diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs index 93b0212a..d510aef3 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContext.cs @@ -1,6 +1,7 @@ using System.Reflection; using SqlSugar; using Volo.Abp.DependencyInjection; +using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.SqlSugarCore; diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContextFactory.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContextFactory.cs index b5623c1c..3012a94c 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContextFactory.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/SqlSugarDbContextFactory.cs @@ -1,10 +1,12 @@ -using System.Reflection; +using System.Collections.Concurrent; +using System.Reflection; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using SqlSugar; using Volo.Abp.Data; using Volo.Abp.DependencyInjection; using Volo.Abp.MultiTenancy; +using Volo.Abp.Threading; using Volo.Abp.Users; using Yi.Framework.SqlSugarCore.Abstractions; using Check = Volo.Abp.Check; @@ -17,6 +19,7 @@ namespace Yi.Framework.SqlSugarCore /// SqlSugar 客户端 /// public ISqlSugarClient SqlSugarClient { get; private set; } + private IAbpLazyServiceProvider LazyServiceProvider { get; } private ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService(); @@ -24,23 +27,29 @@ namespace Yi.Framework.SqlSugarCore private ISerializeService SerializeService => LazyServiceProvider.LazyGetRequiredService(); - private IEnumerable SqlSugarDbContextDependencies=>LazyServiceProvider.LazyGetRequiredService>(); - + private IEnumerable SqlSugarDbContextDependencies => + LazyServiceProvider.LazyGetRequiredService>(); + + private static readonly ConcurrentDictionary ConnectionConfigCache = new(); + public SqlSugarDbContextFactory(IAbpLazyServiceProvider lazyServiceProvider) { LazyServiceProvider = lazyServiceProvider; - + + var connectionString = GetCurrentConnectionString(); + //获取连接配置操作,需要进行缓存 - var connectionConfig = BuildConnectionConfig(action: options => - { - options.ConnectionString = GetCurrentConnectionString(); - options.DbType = GetCurrentDbType(); - }); + var connectionConfig = ConnectionConfigCache.GetOrAdd(connectionString, (_) => + BuildConnectionConfig(action: options => + { + options.ConnectionString = connectionString; + options.DbType = GetCurrentDbType(); + })); SqlSugarClient = new SqlSugarClient(connectionConfig); //生命周期,以下都可以直接使用sqlsugardb了 // Aop及多租户连接字符串和类型,需要单独设置 - // Aop操作需要进行缓存 + // Aop操作不能进行缓存 SetDbAop(SqlSugarClient); } @@ -52,33 +61,32 @@ namespace Yi.Framework.SqlSugarCore { //替换默认序列化器 sqlSugarClient.CurrentConnectionConfig.ConfigureExternalServices.SerializeService = SerializeService; - + //将所有,ISqlSugarDbContextDependencies进行累加 - Action onLogExecuting=null; - Action onLogExecuted=null; + Action onLogExecuting = null; + Action onLogExecuted = null; Action dataExecuting = null; Action dataExecuted = null; Action onSqlSugarClientConfig = null; - - foreach (var dependency in SqlSugarDbContextDependencies.OrderBy(x=>x.ExecutionOrder)) + + foreach (var dependency in SqlSugarDbContextDependencies.OrderBy(x => x.ExecutionOrder)) { - onLogExecuting+= dependency.OnLogExecuting; + onLogExecuting += dependency.OnLogExecuting; onLogExecuted += dependency.OnLogExecuted; dataExecuting += dependency.DataExecuting; dataExecuted += dependency.DataExecuted; onSqlSugarClientConfig += dependency.OnSqlSugarClientConfig; } + //最先存放db操作 onSqlSugarClientConfig(sqlSugarClient); - - sqlSugarClient.Aop.OnLogExecuting = onLogExecuting; - sqlSugarClient.Aop.OnLogExecuted =onLogExecuted; - sqlSugarClient.Aop.DataExecuting = dataExecuting; - sqlSugarClient.Aop.DataExecuted = dataExecuted; + sqlSugarClient.Aop.OnLogExecuting =onLogExecuting; + sqlSugarClient.Aop.OnLogExecuted = onLogExecuted; - + sqlSugarClient.Aop.DataExecuting =dataExecuting; + sqlSugarClient.Aop.DataExecuted =dataExecuted; } /// @@ -86,14 +94,17 @@ namespace Yi.Framework.SqlSugarCore /// /// /// - protected virtual ConnectionConfig BuildConnectionConfig(Action? action=null) + protected virtual ConnectionConfig BuildConnectionConfig(Action? action = null) { var dbConnOptions = Options; + #region 组装options + if (dbConnOptions.DbType is null) { throw new ArgumentException("DbType配置为空"); } + var slavaConFig = new List(); if (dbConnOptions.EnabledReadWrite) { @@ -110,12 +121,14 @@ namespace Yi.Framework.SqlSugarCore slavaConFig.Add(new SlaveConnectionConfig() { ConnectionString = s }); }); } + #endregion #region 组装连接config + var connectionConfig = new ConnectionConfig() { - ConfigId= ConnectionStrings.DefaultConnectionStringName, + ConfigId = ConnectionStrings.DefaultConnectionStringName, DbType = dbConnOptions.DbType ?? DbType.Sqlite, ConnectionString = dbConnOptions.Url, IsAutoCloseConnection = true, @@ -127,27 +140,28 @@ namespace Yi.Framework.SqlSugarCore EntityNameService = (type, entity) => { if (dbConnOptions.EnableUnderLine && !entity.DbTableName.Contains('_')) - entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName);// 驼峰转下划线 + entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName); // 驼峰转下划线 }, EntityService = (c, p) => { if (new NullabilityInfoContext() - .Create(c).WriteState is NullabilityState.Nullable) + .Create(c).WriteState is NullabilityState.Nullable) { p.IsNullable = true; } if (dbConnOptions.EnableUnderLine && !p.IsIgnore && !p.DbColumnName.Contains('_')) - p.DbColumnName = UtilMethods.ToUnderLine(p.DbColumnName);// 驼峰转下划线 - + p.DbColumnName = UtilMethods.ToUnderLine(p.DbColumnName); // 驼峰转下划线 + //将所有,ISqlSugarDbContextDependencies的EntityService进行累加 //额外的实体服务需要这里配置, Action entityService = null; - foreach (var dependency in SqlSugarDbContextDependencies.OrderBy(x=>x.ExecutionOrder)) + foreach (var dependency in SqlSugarDbContextDependencies.OrderBy(x => x.ExecutionOrder)) { entityService += dependency.EntityService; } + entityService(c, p); } }, @@ -165,10 +179,12 @@ namespace Yi.Framework.SqlSugarCore { action.Invoke(connectionConfig); } + #endregion + return connectionConfig; } - + /// /// db切换多库支持 /// @@ -177,7 +193,7 @@ namespace Yi.Framework.SqlSugarCore { var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService(); var connectionString = - connectionStringResolver.ResolveAsync().ConfigureAwait(false).GetAwaiter().GetResult(); + AsyncHelper.RunSync(() => connectionStringResolver.ResolveAsync()); if (string.IsNullOrWhiteSpace(connectionString)) { @@ -230,7 +246,7 @@ namespace Yi.Framework.SqlSugarCore // 条件不满足时返回 null return null; } - + public virtual void BackupDataBase() { diff --git a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs index d86d07f2..7cc138ac 100644 --- a/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs +++ b/Yi.Abp.Net8/framework/Yi.Framework.SqlSugarCore/YiFrameworkSqlSugarCoreModule.cs @@ -6,12 +6,9 @@ using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using SqlSugar; -using Volo.Abp; -using Volo.Abp.Auditing; using Volo.Abp.Data; using Volo.Abp.Domain; using Volo.Abp.Domain.Repositories; -using Volo.Abp.Modularity; using Yi.Framework.SqlSugarCore.Abstractions; using Yi.Framework.SqlSugarCore.Repositories; using Yi.Framework.SqlSugarCore.Uow; @@ -47,6 +44,7 @@ namespace Yi.Framework.SqlSugarCore //将默认db传递给abp连接字符串模块 Configure(x => { x.ConnectionStrings.Default = dbConfig.Url; }); + context.Services.AddYiDbContext(); return Task.CompletedTask; } @@ -72,7 +70,6 @@ namespace Yi.Framework.SqlSugarCore logger.LogInformation(sb.ToString()); - //Todo:准备支持多租户种子数据及CodeFirst if (options.EnabledCodeFirst) { diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index b22be9fb..35106cc5 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -22,10 +22,7 @@ using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.Auditing; using Volo.Abp.Autofac; using Volo.Abp.BackgroundJobs.Hangfire; -using Volo.Abp.BackgroundWorkers; -using Volo.Abp.BackgroundWorkers.Hangfire; using Volo.Abp.Caching; -using Volo.Abp.Hangfire; using Volo.Abp.MultiTenancy; using Volo.Abp.Swashbuckle; using Yi.Abp.Application; @@ -74,7 +71,7 @@ namespace Yi.Abp.Web var configuration = context.Services.GetConfiguration(); var host = context.Services.GetHostingEnvironment(); var service = context.Services; - + //请求日志 Configure(optios => { @@ -87,236 +84,236 @@ namespace Yi.Abp.Web options.IgnoredUrls.Add("/api/app/file/"); options.IgnoredUrls.Add("/hangfire"); }); - + //采用furion格式的规范化api,默认不开启,使用abp优雅的方式 - //你没看错。。。 - //service.AddFurionUnifyResultApi(); + //你没看错。。。 + //service.AddFurionUnifyResultApi(); - //配置错误处理显示详情 - Configure(options => { options.SendExceptionsDetailsToClients = true; }); + //配置错误处理显示详情 + Configure(options => { options.SendExceptionsDetailsToClients = true; }); - //动态Api - Configure(options => + //动态Api + Configure(options => + { + options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly, + options => options.RemoteServiceName = "default"); + options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly, + options => options.RemoteServiceName = "rbac"); + options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly, + options => options.RemoteServiceName = "bbs"); + options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly, + options => options.RemoteServiceName = "chat-hub"); + options.ConventionalControllers.Create( + typeof(YiFrameworkTenantManagementApplicationModule).Assembly, + options => options.RemoteServiceName = "tenant-management"); + options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly, + options => options.RemoteServiceName = "code-gen"); + + //统一前缀 + options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app"); + }); + + //【NewtonsoftJson严重问题!!!!!逆天】设置api格式,留给后人铭记 + // service.AddControllers().AddNewtonsoftJson(options => + // { + // options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + // options.SerializerSettings.Converters.Add(new StringEnumConverter()); + // }); + + //请使用微软的,注意abp date又包了一层,采用DefaultJsonTypeInfoResolver统一覆盖 + Configure(options => + { + options.JsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver(); + options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter()); + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); + }); + + //设置缓存不要过期,默认滑动20分钟 + Configure(cacheOptions => + { + cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null; + //缓存key前缀 + cacheOptions.KeyPrefix = "Yi:"; + }); + + + Configure(options => { options.AutoValidate = false; }); + + //Swagger + context.Services.AddYiSwaggerGen(options => + { + options.SwaggerDoc("default", + new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1", Description = "集大成者" }); + }); + + //跨域 + context.Services.AddCors(options => + { + options.AddPolicy(DefaultCorsPolicyName, builder => { - options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly, - options => options.RemoteServiceName = "default"); - options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly, - options => options.RemoteServiceName = "rbac"); - options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly, - options => options.RemoteServiceName = "bbs"); - options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly, - options => options.RemoteServiceName = "chat-hub"); - options.ConventionalControllers.Create( - typeof(YiFrameworkTenantManagementApplicationModule).Assembly, - options => options.RemoteServiceName = "tenant-management"); - options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly, - options => options.RemoteServiceName = "code-gen"); - - //统一前缀 - options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app"); + builder + .WithOrigins( + configuration["App:CorsOrigins"]! + .Split(";", StringSplitOptions.RemoveEmptyEntries) + .Select(o => o.RemovePostFix("/")) + .ToArray() + ) + .WithAbpExposedHeaders() + .SetIsOriginAllowedToAllowWildcardSubdomains() + .AllowAnyHeader() + .AllowAnyMethod() + .AllowCredentials(); }); + }); - //【NewtonsoftJson严重问题!!!!!逆天】设置api格式,留给后人铭记 - // service.AddControllers().AddNewtonsoftJson(options => - // { - // options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; - // options.SerializerSettings.Converters.Add(new StringEnumConverter()); - // }); + //配置多租户 + Configure(options => + { + //基于cookie jwt不好用,有坑 + options.TenantResolvers.Clear(); + options.TenantResolvers.Add(new HeaderTenantResolveContributor()); + //options.TenantResolvers.Add(new HeaderTenantResolveContributor()); + //options.TenantResolvers.Add(new CookieTenantResolveContributor()); + //options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName); + }); - //请使用微软的,注意abp date又包了一层,采用DefaultJsonTypeInfoResolver统一覆盖 - Configure(options => + //配置Hangfire定时任务存储,开启redis后,优先使用redis + var redisConfiguration = configuration["Redis:Configuration"]; + var redisEnabled = configuration["Redis:IsEnabled"]; + context.Services.AddHangfire(config => + { + if (redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled)) { - options.JsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver(); - options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter()); - options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); - }); - - //设置缓存不要过期,默认滑动20分钟 - Configure(cacheOptions => - { - cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null; - //缓存key前缀 - cacheOptions.KeyPrefix = "Yi:"; - }); - - - Configure(options => { options.AutoValidate = false; }); - - //Swagger - context.Services.AddYiSwaggerGen(options => - { - options.SwaggerDoc("default", - new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1", Description = "集大成者" }); - }); - - //跨域 - context.Services.AddCors(options => - { - options.AddPolicy(DefaultCorsPolicyName, builder => - { - builder - .WithOrigins( - configuration["App:CorsOrigins"]! - .Split(";", StringSplitOptions.RemoveEmptyEntries) - .Select(o => o.RemovePostFix("/")) - .ToArray() - ) - .WithAbpExposedHeaders() - .SetIsOriginAllowedToAllowWildcardSubdomains() - .AllowAnyHeader() - .AllowAnyMethod() - .AllowCredentials(); - }); - }); - - //配置多租户 - Configure(options => - { - //基于cookie jwt不好用,有坑 - options.TenantResolvers.Clear(); - options.TenantResolvers.Add(new HeaderTenantResolveContributor()); - //options.TenantResolvers.Add(new HeaderTenantResolveContributor()); - //options.TenantResolvers.Add(new CookieTenantResolveContributor()); - //options.TenantResolvers.RemoveAll(x => x.Name == CookieTenantResolveContributor.ContributorName); - }); - - //配置Hangfire定时任务存储,开启redis后,优先使用redis - var redisConfiguration = configuration["Redis:Configuration"]; - var redisEnabled = configuration["Redis:IsEnabled"]; - context.Services.AddHangfire(config => - { - if (redisEnabled.IsNullOrEmpty() || bool.Parse(redisEnabled)) - { - config.UseRedisStorage( - ConnectionMultiplexer.Connect(redisConfiguration), - new RedisStorageOptions() - { - InvisibilityTimeout = TimeSpan.FromHours(1), //JOB允许执行1小时 - Prefix = "Yi:HangfireJob:" - }).WithJobExpirationTimeout(TimeSpan.FromHours(1)); - } - else - { - config.UseMemoryStorage(); - } - }); - - //速率限制 - //每60秒限制100个请求,滑块添加,分6段 - service.AddRateLimiter(_ => - { - _.RejectionStatusCode = StatusCodes.Status429TooManyRequests; - _.OnRejected = (context, _) => - { - if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) + config.UseRedisStorage( + ConnectionMultiplexer.Connect(redisConfiguration), + new RedisStorageOptions() { - context.HttpContext.Response.Headers.RetryAfter = - ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); - } + InvisibilityTimeout = TimeSpan.FromHours(1), //JOB允许执行1小时 + Prefix = "Yi:HangfireJob:" + }).WithJobExpirationTimeout(TimeSpan.FromHours(1)); + } + else + { + config.UseMemoryStorage(); + } + }); - context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; - context.HttpContext.Response.WriteAsync("Too many requests. Please try again later."); + //速率限制 + //每60秒限制100个请求,滑块添加,分6段 + service.AddRateLimiter(_ => + { + _.RejectionStatusCode = StatusCodes.Status429TooManyRequests; + _.OnRejected = (context, _) => + { + if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) + { + context.HttpContext.Response.Headers.RetryAfter = + ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); + } - return new ValueTask(); + context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; + context.HttpContext.Response.WriteAsync("Too many requests. Please try again later."); + + return new ValueTask(); + }; + + //全局使用,链式表达式 + _.GlobalLimiter = PartitionedRateLimiter.CreateChained( + PartitionedRateLimiter.Create(httpContext => + { + var userAgent = httpContext.Request.Headers.UserAgent.ToString(); + + return RateLimitPartition.GetSlidingWindowLimiter + (userAgent, _ => + new SlidingWindowRateLimiterOptions + { + PermitLimit = 1000, + Window = TimeSpan.FromSeconds(60), + SegmentsPerWindow = 6, + QueueProcessingOrder = QueueProcessingOrder.OldestFirst + }); + })); + }); + + + //jwt鉴权 + var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get(); + var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get(); + + context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) + .AddJwtBearer(options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ClockSkew = TimeSpan.Zero, + ValidateIssuerSigningKey = true, + ValidIssuer = jwtOptions.Issuer, + ValidAudience = jwtOptions.Audience, + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey)) }; - - //全局使用,链式表达式 - _.GlobalLimiter = PartitionedRateLimiter.CreateChained( - PartitionedRateLimiter.Create(httpContext => - { - var userAgent = httpContext.Request.Headers.UserAgent.ToString(); - - return RateLimitPartition.GetSlidingWindowLimiter - (userAgent, _ => - new SlidingWindowRateLimiterOptions - { - PermitLimit = 1000, - Window = TimeSpan.FromSeconds(60), - SegmentsPerWindow = 6, - QueueProcessingOrder = QueueProcessingOrder.OldestFirst - }); - })); - }); - - - //jwt鉴权 - var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get(); - var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get(); - - context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) - .AddJwtBearer(options => + options.Events = new JwtBearerEvents { - options.TokenValidationParameters = new TokenValidationParameters + OnMessageReceived = context => { - ClockSkew = TimeSpan.Zero, - ValidateIssuerSigningKey = true, - ValidIssuer = jwtOptions.Issuer, - ValidAudience = jwtOptions.Audience, - IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey)) - }; - options.Events = new JwtBearerEvents - { - OnMessageReceived = context => + //优先Query中获取,再去cookies中获取 + var accessToken = context.Request.Query["access_token"]; + if (!string.IsNullOrEmpty(accessToken)) { - //优先Query中获取,再去cookies中获取 - var accessToken = context.Request.Query["access_token"]; - if (!string.IsNullOrEmpty(accessToken)) + context.Token = accessToken; + } + else + { + if (context.Request.Cookies.TryGetValue("Token", out var cookiesToken)) { - context.Token = accessToken; - } - else - { - if (context.Request.Cookies.TryGetValue("Token",out var cookiesToken)) - { - context.Token = cookiesToken; - } + context.Token = cookiesToken; } + } + + return Task.CompletedTask; + } + }; + }) + .AddJwtBearer(TokenTypeConst.Refresh, options => + { + options.TokenValidationParameters = new TokenValidationParameters + { + ClockSkew = TimeSpan.Zero, + ValidateIssuerSigningKey = true, + ValidIssuer = refreshJwtOptions.Issuer, + ValidAudience = refreshJwtOptions.Audience, + IssuerSigningKey = + new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey)) + }; + options.Events = new JwtBearerEvents + { + OnMessageReceived = context => + { + var refresh_token = context.Request.Headers["refresh_token"]; + if (!string.IsNullOrEmpty(refresh_token)) + { + context.Token = refresh_token; return Task.CompletedTask; } - }; - }) - .AddJwtBearer(TokenTypeConst.Refresh, options => - { - options.TokenValidationParameters = new TokenValidationParameters - { - ClockSkew = TimeSpan.Zero, - ValidateIssuerSigningKey = true, - ValidIssuer = refreshJwtOptions.Issuer, - ValidAudience = refreshJwtOptions.Audience, - IssuerSigningKey = - new SymmetricSecurityKey(Encoding.UTF8.GetBytes(refreshJwtOptions.SecurityKey)) - }; - options.Events = new JwtBearerEvents - { - OnMessageReceived = context => + + var refreshToken = context.Request.Query["refresh_token"]; + if (!string.IsNullOrEmpty(refreshToken)) { - var refresh_token = context.Request.Headers["refresh_token"]; - if (!string.IsNullOrEmpty(refresh_token)) - { - context.Token = refresh_token; - return Task.CompletedTask; - } - - var refreshToken = context.Request.Query["refresh_token"]; - if (!string.IsNullOrEmpty(refreshToken)) - { - context.Token = refreshToken; - } - - return Task.CompletedTask; + context.Token = refreshToken; } - }; - }) - .AddQQ(options => { configuration.GetSection("OAuth:QQ").Bind(options); }) - .AddGitee(options => { configuration.GetSection("OAuth:Gitee").Bind(options); }); - //授权 - context.Services.AddAuthorization(); + return Task.CompletedTask; + } + }; + }) + .AddQQ(options => { configuration.GetSection("OAuth:QQ").Bind(options); }) + .AddGitee(options => { configuration.GetSection("OAuth:Gitee").Bind(options); }); - - - return Task.CompletedTask; - } + //授权 + context.Services.AddAuthorization(); + + + return Task.CompletedTask; + } public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) @@ -373,12 +370,13 @@ namespace Yi.Abp.Web //日志记录 app.UseAbpSerilogEnrichers(); - + //Hangfire定时任务面板,可配置授权,意框架支持jwt - app.UseAbpHangfireDashboard("/hangfire", options => - { - options.AsyncAuthorization = new[] { new YiTokenAuthorizationFilter(app.ApplicationServices) }; - }); + app.UseAbpHangfireDashboard("/hangfire", + options => + { + options.AsyncAuthorization = new[] { new YiTokenAuthorizationFilter(app.ApplicationServices) }; + }); //终节点 app.UseConfiguredEndpoints();