diff --git a/Yi.Abp.Net8/Yi.Abp.sln b/Yi.Abp.Net8/Yi.Abp.sln index 19d7412b..f84b1031 100644 --- a/Yi.Abp.Net8/Yi.Abp.sln +++ b/Yi.Abp.Net8/Yi.Abp.sln @@ -170,6 +170,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollect EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.WeChat.MiniProgram", "framework\Yi.Framework.WeChat.MiniProgram\Yi.Framework.WeChat.MiniProgram.csproj", "{81CEA2ED-917B-41D8-BE0D-39A785B050C0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.BackgroundWorkers.Hangfire", "framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj", "{862CA181-BEE6-4870-82D2-B662E527ED8C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -428,6 +430,10 @@ Global {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|Any CPU.Build.0 = Debug|Any CPU {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.ActiveCfg = Release|Any CPU {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.Build.0 = Release|Any CPU + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {862CA181-BEE6-4870-82D2-B662E527ED8C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -504,6 +510,7 @@ Global {FFEC9DA6-1A13-480A-AE9E-2BF8763D3061} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C} {4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C} {81CEA2ED-917B-41D8-BE0D-39A785B050C0} = {77B949E9-530E-45A5-9657-20F7D5C6875C} + {862CA181-BEE6-4870-82D2-B662E527ED8C} = {77B949E9-530E-45A5-9657-20F7D5C6875C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18} diff --git a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/Yi.Framework.BackgroundWorkers.Hangfire.csproj b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/Yi.Framework.BackgroundWorkers.Hangfire.csproj new file mode 100644 index 00000000..ee6c5ed7 --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/Yi.Framework.BackgroundWorkers.Hangfire.csproj @@ -0,0 +1,17 @@ + + + + + + net8.0 + enable + enable + + + + + + + + + diff --git a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiFrameworkBackgroundWorkersHangfireModule.cs b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiFrameworkBackgroundWorkersHangfireModule.cs new file mode 100644 index 00000000..b4aae0c3 --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiFrameworkBackgroundWorkersHangfireModule.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.BackgroundWorkers; +using Volo.Abp.BackgroundWorkers.Hangfire; + +namespace Yi.Framework.BackgroundWorkers.Hangfire; + +[DependsOn(typeof(AbpBackgroundWorkersHangfireModule))] +public class YiFrameworkBackgroundWorkersHangfireModule:AbpModule +{ + public override void PreConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddConventionalRegistrar(new YiHangfireConventionalRegistrar()); + } + + public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + { + //定时任务自动注入,Abp默认只有在Quartz才实现 + var backgroundWorkerManager = context.ServiceProvider.GetRequiredService(); + var works = context.ServiceProvider.GetServices(); + + foreach (var work in works) + { + await backgroundWorkerManager.AddAsync(work); + } + + } +} \ No newline at end of file diff --git a/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiHangfireConventionalRegistrar.cs b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiHangfireConventionalRegistrar.cs new file mode 100644 index 00000000..f8f99bad --- /dev/null +++ b/Yi.Abp.Net8/framework/Yi.Framework.BackgroundWorkers.Hangfire/YiHangfireConventionalRegistrar.cs @@ -0,0 +1,20 @@ +using Volo.Abp.BackgroundWorkers.Hangfire; +using Volo.Abp.DependencyInjection; + +namespace Yi.Framework.BackgroundWorkers.Hangfire; + +public class YiHangfireConventionalRegistrar : DefaultConventionalRegistrar +{ + protected override bool IsConventionalRegistrationDisabled(Type type) + { + return !typeof(IHangfireBackgroundWorker).IsAssignableFrom(type) || base.IsConventionalRegistrationDisabled(type); + } + + protected override List GetExposedServiceTypes(Type type) + { + return new List() + { + typeof(IHangfireBackgroundWorker) + }; + } +} diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogCacheJob.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogCacheJob.cs index ddedea02..63b3b4d0 100644 --- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogCacheJob.cs +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogCacheJob.cs @@ -1,8 +1,8 @@ using FreeRedis; +using Hangfire; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; -using Quartz; -using Volo.Abp.BackgroundWorkers.Quartz; +using Volo.Abp.BackgroundWorkers.Hangfire; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Volo.Abp.Domain.Entities; @@ -15,23 +15,27 @@ using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.Bbs.Application.Jobs; -public class AccessLogCacheJob : QuartzBackgroundWorkerBase +public class AccessLogCacheJob : HangfireBackgroundWorkerBase { private readonly ILocalEventBus _localEventBus; public AccessLogCacheJob(ILocalEventBus localEventBus) { _localEventBus = localEventBus; - JobDetail = JobBuilder.Create().WithIdentity(nameof(AccessLogCacheJob)) - .Build(); + RecurringJobId = "访问日志写入缓存"; + //每10秒执行一次,将本地缓存转入redis,防止丢数据 + CronExpression = "*/10 * * * * *"; + // + // JobDetail = JobBuilder.Create().WithIdentity(nameof(AccessLogCacheJob)) + // .Build(); //每10秒执行一次,将本地缓存转入redis,防止丢数据 - Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogCacheJob)) - .WithSimpleSchedule((schedule) => { schedule.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever(); }) - .Build(); + // Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogCacheJob)) + // .WithSimpleSchedule((schedule) => { schedule.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever();; }) + // .Build(); } - - public override async Task Execute(IJobExecutionContext context) + + public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken()) { await _localEventBus.PublishAsync(new AccessLogResetArgs()); } diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogStoreJob.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogStoreJob.cs index 66cc24d5..8fb30491 100644 --- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogStoreJob.cs +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogStoreJob.cs @@ -1,11 +1,9 @@ using FreeRedis; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Options; -using Quartz; -using Volo.Abp.BackgroundWorkers.Quartz; +using Volo.Abp.BackgroundWorkers.Hangfire; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; -using Volo.Abp.Domain.Entities; using Yi.Framework.Bbs.Domain.Entities; using Yi.Framework.Bbs.Domain.Shared.Caches; using Yi.Framework.Bbs.Domain.Shared.Enums; @@ -13,7 +11,7 @@ using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.Bbs.Application.Jobs; -public class AccessLogStoreJob : QuartzBackgroundWorkerBase +public class AccessLogStoreJob : HangfireBackgroundWorkerBase { private readonly ISqlSugarRepository _repository; @@ -45,18 +43,23 @@ public class AccessLogStoreJob : QuartzBackgroundWorkerBase public AccessLogStoreJob(ISqlSugarRepository repository) { _repository = repository; - JobDetail = JobBuilder.Create().WithIdentity(nameof(AccessLogStoreJob)) - .Build(); + + RecurringJobId = "访问日志写入数据库"; //每分钟执行一次 - Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogStoreJob)) - .WithCronSchedule("0 * * * * ?") - .Build(); + CronExpression = "0 * * * * ?"; + // JobDetail = JobBuilder.Create().WithIdentity(nameof(AccessLogStoreJob)) + // .Build(); + // //每分钟执行一次 + // Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogStoreJob)) + // .WithCronSchedule("0 * * * * ?") + // .Build(); } + - public override async Task Execute(IJobExecutionContext context) + public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken()) { if (EnableRedisCache) { diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AssignmentExpireTimeOutJob.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AssignmentExpireTimeOutJob.cs index 937fb689..1238c979 100644 --- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AssignmentExpireTimeOutJob.cs +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AssignmentExpireTimeOutJob.cs @@ -1,5 +1,4 @@ -using Quartz; -using Volo.Abp.BackgroundWorkers.Quartz; +using Volo.Abp.BackgroundWorkers.Hangfire; using Yi.Framework.Bbs.Domain.Managers; namespace Yi.Framework.Bbs.Application.Jobs; @@ -7,20 +6,25 @@ namespace Yi.Framework.Bbs.Application.Jobs; /// /// 每日任务job /// -public class AssignmentExpireTimeOutJob : QuartzBackgroundWorkerBase +public class AssignmentExpireTimeOutJob : HangfireBackgroundWorkerBase { private readonly AssignmentManager _assignmentManager; public AssignmentExpireTimeOutJob(AssignmentManager assignmentManager) { _assignmentManager = assignmentManager; - JobDetail = JobBuilder.Create().WithIdentity(nameof(AssignmentExpireTimeOutJob)).Build(); - //每个小时整点执行一次 - Trigger = TriggerBuilder.Create().WithIdentity(nameof(AssignmentExpireTimeOutJob)).WithCronSchedule("0 0 * * * ?") - .Build(); + + RecurringJobId = "每日任务系统超时检测"; + //每分钟执行一次 + CronExpression = "0 * * * * ?"; + // + // JobDetail = JobBuilder.Create().WithIdentity(nameof(AssignmentExpireTimeOutJob)).Build(); + // //每个小时整点执行一次 + // Trigger = TriggerBuilder.Create().WithIdentity(nameof(AssignmentExpireTimeOutJob)).WithCronSchedule("0 0 * * * ?") + // .Build(); } - - public override async Task Execute(IJobExecutionContext context) + + public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken()) { await _assignmentManager.ExpireTimeoutAsync(); } diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/InterestRecordsJob.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/InterestRecordsJob.cs index 80837a9e..85bfafdd 100644 --- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/InterestRecordsJob.cs +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/InterestRecordsJob.cs @@ -1,20 +1,24 @@ -using Quartz; -using Volo.Abp.BackgroundWorkers.Quartz; +using Volo.Abp.BackgroundWorkers.Hangfire; using Yi.Framework.Bbs.Domain.Managers; namespace Yi.Framework.Bbs.Application.Jobs { - public class InterestRecordsJob : QuartzBackgroundWorkerBase + public class InterestRecordsJob : HangfireBackgroundWorkerBase { private BankManager _bankManager; public InterestRecordsJob(BankManager bankManager) { _bankManager = bankManager; - JobDetail = JobBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).Build(); - + + RecurringJobId = "银行利息积分刷新"; //每个小时整点执行一次 - - Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).WithCronSchedule("0 0 * * * ?").Build(); + CronExpression = "0 0 * * * ?"; + + // JobDetail = JobBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).Build(); + // + // //每个小时整点执行一次 + // + // Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).WithCronSchedule("0 0 * * * ?").Build(); //测试 // Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)) @@ -23,7 +27,8 @@ namespace Yi.Framework.Bbs.Application.Jobs // .RepeatForever()) //.Build(); } - public override async Task Execute(IJobExecutionContext context) + + public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken()) { //创建一个记录,莫得了 await _bankManager.GetCurrentInterestRate(); diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/BbsUserInfoService.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/BbsUserInfoService.cs index 0e93ced2..91c0c739 100644 --- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/BbsUserInfoService.cs +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/BbsUserInfoService.cs @@ -27,13 +27,19 @@ namespace Yi.Framework.Bbs.Application.Services var userEntity = await _bbsUserManager._userRepository.GetFirstAsync(x => x.UserName == userNameOrUserId); if (userEntity == null) { - throw new Volo.Abp.UserFriendlyException("该用户不存在"); + throw new UserFriendlyException("该用户不存在"); } userId= userEntity.Id; } var output =await _bbsUserManager.GetBbsUserInfoAsync(userId); - + + //不是自己 + if (CurrentUser.Id != output.Id) + { + output.Phone = null; + output.Email=null; + } return output!; } } diff --git a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/Forum/CommentService.cs b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/Forum/CommentService.cs index 52db5120..b8926f13 100644 --- a/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/Forum/CommentService.cs +++ b/Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Services/Forum/CommentService.cs @@ -136,6 +136,11 @@ namespace Yi.Framework.Bbs.Application.Services.Forum [Authorize] public override async Task CreateAsync(CommentCreateInputVo input) { + if (input.Content.Length<=6) + { + throw new UserFriendlyException("评论长度至少大于6"); + } + var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId); if (discuess is null) { diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Jobs/BackupDataBaseJob.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Jobs/BackupDataBaseJob.cs index 7db58b06..88398f87 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Jobs/BackupDataBaseJob.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Jobs/BackupDataBaseJob.cs @@ -6,16 +6,14 @@ using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Quartz; -using Quartz.Logging; -using Volo.Abp.BackgroundWorkers.Quartz; +using Volo.Abp.BackgroundWorkers.Hangfire; using Volo.Abp.Domain.Repositories; using Yi.Framework.Rbac.Domain.Shared.Options; using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.Rbac.Application.Jobs { - public class BackupDataBaseJob : QuartzBackgroundWorkerBase + public class BackupDataBaseJob: HangfireBackgroundWorkerBase { private ISqlSugarDbContext _dbContext; private IOptions _options; @@ -24,13 +22,12 @@ namespace Yi.Framework.Rbac.Application.Jobs _options = options; _dbContext = dbContext; - JobDetail = JobBuilder.Create().WithIdentity(nameof(BackupDataBaseJob)).Build(); - + + RecurringJobId = "数据库备份"; //每天00点与24点进行备份 - Trigger = TriggerBuilder.Create().WithIdentity(nameof(BackupDataBaseJob)).WithCronSchedule("0 0 0,12 * * ? ").Build(); - //Trigger = TriggerBuilder.Create().WithIdentity(nameof(BackupDataBaseJob)).WithSimpleSchedule(x=>x.WithIntervalInSeconds(10)).Build(); + CronExpression = "0 0 0,12 * * ? "; } - public override Task Execute(IJobExecutionContext context) + public override Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken()) { if (_options.Value.EnableDataBaseBackup) { diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/TaskService.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/TaskService.cs deleted file mode 100644 index ab857fb6..00000000 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Services/Monitor/TaskService.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System.Reflection; -using Mapster; -using Microsoft.AspNetCore.Mvc; -using Quartz; -using Quartz.Impl.Matchers; -using Volo.Abp; -using Volo.Abp.Application.Dtos; -using Volo.Abp.Application.Services; -using Volo.Abp.Timing; -using Yi.Framework.Rbac.Application.Contracts.Dtos.Task; -using Yi.Framework.Rbac.Application.Contracts.IServices; -using Yi.Framework.Rbac.Domain.Shared.Enums; - -namespace Yi.Framework.Rbac.Application.Services.Monitor -{ - public class TaskService : ApplicationService, ITaskService - { - private readonly ISchedulerFactory _schedulerFactory; - private readonly IClock _clock; - public TaskService(ISchedulerFactory schedulerFactory, IClock clock) - { - _clock = clock; - _schedulerFactory = schedulerFactory; - } - - - /// - /// 单查job - /// - /// - /// - [HttpGet("task/{jobId}")] - public async Task GetAsync([FromRoute] string jobId) - { - var scheduler = await _schedulerFactory.GetScheduler(); - - var jobDetail = await scheduler.GetJobDetail(new JobKey(jobId)); - var trigger = (await scheduler.GetTriggersOfJob(new JobKey(jobId))).First(); - //状态 - var state = await scheduler.GetTriggerState(trigger.Key); - - - var output = new TaskGetOutput - { - JobId = jobDetail.Key.Name, - GroupName = jobDetail.Key.Group, - JobType = jobDetail.JobType.Name, - Properties = Newtonsoft.Json.JsonConvert.SerializeObject(jobDetail.JobDataMap), - Concurrent = !jobDetail.ConcurrentExecutionDisallowed, - Description = jobDetail.Description, - LastRunTime = _clock.Normalize(trigger.GetPreviousFireTimeUtc()?.DateTime ?? DateTime.MinValue), - NextRunTime = _clock.Normalize(trigger.GetNextFireTimeUtc()?.DateTime ?? DateTime.MinValue), - AssemblyName = jobDetail.JobType.Assembly.GetName().Name, - Status = state.ToString() - }; - - if (trigger is ISimpleTrigger simple) - { - output.TriggerArgs = Math.Round(simple.RepeatInterval.TotalMinutes, 2).ToString() + "分钟"; - output.Type = JobTypeEnum.Millisecond; - output.Millisecond = simple.RepeatInterval.TotalMilliseconds; - } - else if (trigger is ICronTrigger cron) - { - output.TriggerArgs = cron.CronExpressionString!; - output.Type = JobTypeEnum.Cron; - output.Cron = cron.CronExpressionString; - } - return output; - } - - /// - /// 多查job - /// - /// - public async Task> GetListAsync([FromQuery] TaskGetListInput input) - { - var items = new List(); - - var scheduler = await _schedulerFactory.GetScheduler(); - - var groups = await scheduler.GetJobGroupNames(); - - foreach (var groupName in groups) - { - foreach (var jobKey in await scheduler.GetJobKeys(GroupMatcher.GroupEquals(groupName))) - { - string jobName = jobKey.Name; - string jobGroup = jobKey.Group; - var triggers = (await scheduler.GetTriggersOfJob(jobKey)).First(); - items.Add(await GetAsync(jobName)); - } - } - - - var output = items.Skip((input.SkipCount - 1) * input.MaxResultCount).Take(input.MaxResultCount) - .OrderByDescending(x => x.LastRunTime) - .ToList(); - return new PagedResultDto(items.Count(), output.Adapt>()); - } - - /// - /// 创建job - /// - /// - /// - public async Task CreateAsync(TaskCreateInput input) - { - var scheduler = await _schedulerFactory.GetScheduler(); - - //设置启动时执行一次,然后最大只执行一次 - - - //jobBuilder - var jobClassType = Assembly.Load(input.AssemblyName).GetTypes().Where(x => x.Name == input.JobType).FirstOrDefault(); - - if (jobClassType is null) - { - throw new UserFriendlyException($"程序集:{input.AssemblyName},{input.JobType} 不存在"); - } - - var jobBuilder = JobBuilder.Create(jobClassType).WithIdentity(new JobKey(input.JobId, input.GroupName)) - .WithDescription(input.Description); - if (!input.Concurrent) - { - jobBuilder.DisallowConcurrentExecution(); - } - - //triggerBuilder - TriggerBuilder triggerBuilder = null; - switch (input.Type) - { - case JobTypeEnum.Cron: - triggerBuilder = - TriggerBuilder.Create() - .WithCronSchedule(input.Cron); - - - - - break; - case JobTypeEnum.Millisecond: - triggerBuilder = - TriggerBuilder.Create().StartNow() - .WithSimpleSchedule(x => x - .WithInterval(TimeSpan.FromMilliseconds(input.Millisecond ?? 10000)) - .RepeatForever() - ); - break; - } - - //作业计划,单个jobBuilder与多个triggerBuilder组合 - await scheduler.ScheduleJob(jobBuilder.Build(), triggerBuilder.Build()); - } - - /// - /// 移除job - /// - /// - /// - public async Task DeleteAsync(IEnumerable id) - { - var scheduler = await _schedulerFactory.GetScheduler(); - await scheduler.DeleteJobs(id.Select(x => new JobKey(x)).ToList()); - } - - /// - /// 暂停job - /// - /// - /// - [HttpPut] - public async Task PauseAsync(string jobId) - { - var scheduler = await _schedulerFactory.GetScheduler(); - await scheduler.PauseJob(new JobKey(jobId)); - } - - /// - /// 开始job - /// - /// - /// - [HttpPut] - public async Task StartAsync(string jobId) - { - var scheduler = await _schedulerFactory.GetScheduler(); - await scheduler.ResumeJob(new JobKey(jobId)); - } - - /// - /// 更新job - /// - /// - /// - /// - public async Task UpdateAsync(string id, TaskUpdateInput input) - { - await DeleteAsync(new List() { id }); - await CreateAsync(input.Adapt()); - } - - [HttpPost("task/run-once/{id}")] - public async Task RunOnceAsync([FromRoute] string id) - { - var scheduler = await _schedulerFactory.GetScheduler(); - var jobDetail = await scheduler.GetJobDetail(new JobKey(id)); - - var jobBuilder = JobBuilder.Create(jobDetail.JobType).WithIdentity(new JobKey(Guid.NewGuid().ToString())); - //设置启动时执行一次,然后最大只执行一次 - var trigger = TriggerBuilder.Create().WithIdentity(Guid.NewGuid().ToString()).StartNow() - .WithSimpleSchedule(x => x - .WithIntervalInHours(1) - .WithRepeatCount(1)) - .Build(); - - await scheduler.ScheduleJob(jobBuilder.Build(), trigger); - } - } -} diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Yi.Framework.Rbac.Application.csproj b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Yi.Framework.Rbac.Application.csproj index b9536345..81a3a0d9 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Yi.Framework.Rbac.Application.csproj +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/Yi.Framework.Rbac.Application.csproj @@ -10,13 +10,15 @@ - + + + diff --git a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/YiFrameworkRbacApplicationModule.cs b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/YiFrameworkRbacApplicationModule.cs index 13d07949..c06f32cd 100644 --- a/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/YiFrameworkRbacApplicationModule.cs +++ b/Yi.Abp.Net8/module/rbac/Yi.Framework.Rbac.Application/YiFrameworkRbacApplicationModule.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Volo.Abp; using Volo.Abp.BackgroundWorkers; -using Volo.Abp.BackgroundWorkers.Quartz; +using Volo.Abp.BackgroundWorkers.Hangfire; using Volo.Abp.Modularity; using Yi.Framework.Ddd.Application; using Yi.Framework.Rbac.Application.Contracts; @@ -16,8 +16,7 @@ namespace Yi.Framework.Rbac.Application typeof(YiFrameworkRbacDomainModule), - typeof(YiFrameworkDddApplicationModule), - typeof(AbpBackgroundWorkersQuartzModule) + typeof(YiFrameworkDddApplicationModule) )] public class YiFrameworkRbacApplicationModule : AbpModule { @@ -28,7 +27,6 @@ namespace Yi.Framework.Rbac.Application service.AddCaptcha(options => { options.CaptchaType = CaptchaType.ARITHMETIC; - }); } diff --git a/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/DemoResetJob.cs b/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/DemoResetJob.cs new file mode 100644 index 00000000..86c60a08 --- /dev/null +++ b/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/DemoResetJob.cs @@ -0,0 +1,53 @@ +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Logging; +using Volo.Abp.BackgroundWorkers.Hangfire; +using Volo.Abp.Data; +using Yi.Framework.Rbac.Domain.Entities; +using Yi.Framework.SqlSugarCore.Abstractions; + +namespace Yi.Abp.Application.Jobs +{ + public class DemoResetJob : HangfireBackgroundWorkerBase + { + private ISqlSugarDbContext _dbContext; + private ILogger _logger => LoggerFactory.CreateLogger(); + private IDataSeeder _dataSeeder; + private IConfiguration _configuration; + public DemoResetJob(ISqlSugarDbContext dbContext, IDataSeeder dataSeeder, IConfiguration configuration) + { + _dbContext = dbContext; + RecurringJobId = "重置demo环境"; + //每天1点和13点进行重置demo环境 + CronExpression = "0 0 1,13 * * ?"; + + _dataSeeder = dataSeeder; + _configuration = configuration; + } + + public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken()) + { + //开启演示环境重置功能 + if (_configuration.GetSection("EnableDemoReset").Get()) + { + //定时任务,非常简单 + _logger.LogWarning("演示环境正在还原!"); + var db = _dbContext.SqlSugarClient.CopyNew(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + db.DbMaintenance.TruncateTable(); + + //删除种子数据 + await _dataSeeder.SeedAsync(); + _logger.LogWarning("演示环境还原成功!"); + + } + + } + } +} diff --git a/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/TestJob.cs b/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/TestJob.cs index e0b68065..9c098146 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/TestJob.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/TestJob.cs @@ -1,6 +1,6 @@ -using Quartz; +using Hangfire; using SqlSugar; -using Volo.Abp.BackgroundWorkers.Quartz; +using Volo.Abp.BackgroundWorkers.Hangfire; using Volo.Abp.Domain.Repositories; using Volo.Abp.Uow; using Yi.Framework.Rbac.Domain.Entities; @@ -11,26 +11,21 @@ namespace Yi.Abp.Application.Jobs /// /// 定时任务 /// - public class TestJob : QuartzBackgroundWorkerBase + public class TestJob : HangfireBackgroundWorkerBase { private ISqlSugarRepository _repository; public TestJob(ISqlSugarRepository repository) { _repository = repository; - JobDetail = JobBuilder.Create().WithIdentity(nameof(TestJob)).Build(); - Trigger = TriggerBuilder.Create().WithIdentity(nameof(TestJob)).StartNow() - .WithSimpleSchedule(x => x - .WithIntervalInSeconds(1000 * 60) - .RepeatForever()) - .Build(); + RecurringJobId = "测试"; + //每天一次 + CronExpression = Cron.Daily(); } - public override async Task Execute(IJobExecutionContext context) + public override Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken()) { //定时任务,非常简单 Console.WriteLine("你好,世界"); - // var eneities= await _repository.GetListAsync(); - //var entities= await _sqlSugarClient.Queryable().ToListAsync(); - //await Console.Out.WriteLineAsync(entities.Count().ToString()); + return Task.CompletedTask; } } } diff --git a/Yi.Abp.Net8/src/Yi.Abp.Application/Yi.Abp.Application.csproj b/Yi.Abp.Net8/src/Yi.Abp.Application/Yi.Abp.Application.csproj index 1e3004b7..b63ee650 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Application/Yi.Abp.Application.csproj +++ b/Yi.Abp.Net8/src/Yi.Abp.Application/Yi.Abp.Application.csproj @@ -3,6 +3,7 @@ + diff --git a/Yi.Abp.Net8/src/Yi.Abp.Application/YiAbpApplicationModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Application/YiAbpApplicationModule.cs index 10a5ec75..679cfa36 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Application/YiAbpApplicationModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Application/YiAbpApplicationModule.cs @@ -1,6 +1,7 @@ using Volo.Abp.SettingManagement; using Yi.Abp.Application.Contracts; using Yi.Abp.Domain; +using Yi.Framework.BackgroundWorkers.Hangfire; using Yi.Framework.Bbs.Application; using Yi.Framework.ChatHub.Application; using Yi.Framework.CodeGen.Application; @@ -25,7 +26,8 @@ namespace Yi.Abp.Application typeof(YiFrameworkCodeGenApplicationModule), typeof (YiFrameworkSettingManagementApplicationModule), - typeof(YiFrameworkDddApplicationModule) + typeof(YiFrameworkDddApplicationModule), + typeof(YiFrameworkBackgroundWorkersHangfireModule) )] public class YiAbpApplicationModule : AbpModule { diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/Yi.Abp.Web.csproj b/Yi.Abp.Net8/src/Yi.Abp.Web/Yi.Abp.Web.csproj index f50d8a24..2623b61f 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/Yi.Abp.Web.csproj +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/Yi.Abp.Web.csproj @@ -8,6 +8,8 @@ + + diff --git a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs index f1ab5ae7..bcce54e0 100644 --- a/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs +++ b/Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs @@ -3,6 +3,9 @@ using System.Text; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; using System.Threading.RateLimiting; +using Hangfire; +using Hangfire.MemoryStorage; +using Hangfire.Redis.StackExchange; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; @@ -12,20 +15,21 @@ using Microsoft.AspNetCore.StaticFiles; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using Microsoft.OpenApi.Models; -using Newtonsoft.Json.Converters; +using StackExchange.Redis; +using Volo.Abp.AspNetCore.Auditing; using Volo.Abp.AspNetCore.Authentication.JwtBearer; using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc.AntiForgery; -using Volo.Abp.AspNetCore.Mvc.ExceptionHandling; using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.AspNetCore.VirtualFileSystem; 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.Json; -using Volo.Abp.Json.SystemTextJson; using Volo.Abp.MultiTenancy; using Volo.Abp.Swashbuckle; using Yi.Abp.Application; @@ -36,7 +40,7 @@ using Yi.Framework.AspNetCore.Authentication.OAuth.Gitee; using Yi.Framework.AspNetCore.Authentication.OAuth.QQ; using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder; using Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection; -using Yi.Framework.AspNetCore.UnifyResult; +using Yi.Framework.BackgroundWorkers.Hangfire; using Yi.Framework.Bbs.Application; using Yi.Framework.Bbs.Application.Extensions; using Yi.Framework.ChatHub.Application; @@ -60,6 +64,8 @@ namespace Yi.Abp.Web typeof(AbpSwashbuckleModule), typeof(AbpAspNetCoreSerilogModule), typeof(AbpAuditingModule), + typeof(YiFrameworkBackgroundWorkersHangfireModule), + typeof(AbpBackgroundJobsHangfireModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(YiFrameworkAspNetCoreModule), typeof(YiFrameworkAspNetCoreAuthenticationOAuthModule) @@ -73,21 +79,26 @@ namespace Yi.Abp.Web var configuration = context.Services.GetConfiguration(); var host = context.Services.GetHostingEnvironment(); var service = context.Services; + //请求日志 Configure(optios => { //默认关闭,开启会有大量的审计日志 optios.IsEnabled = true; - //审计日志过滤器,符合条件的才记录 - optios.AlwaysLogSelectors.Add(x => Task.FromResult(x.Url is null?true:!x.Url.StartsWith("/api/app/file/"))); }); - + //忽略审计日志路径 + Configure(options => + { + 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 => @@ -110,181 +121,203 @@ namespace Yi.Abp.Web 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()); - }); + //【NewtonsoftJson严重问题!!!!!逆天】设置api格式,留给后人铭记 + // service.AddControllers().AddNewtonsoftJson(options => + // { + // options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + // options.SerializerSettings.Converters.Add(new StringEnumConverter()); + // }); - //设置缓存不要过期,默认滑动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 => + //请使用微软的,注意abp date又包了一层,采用DefaultJsonTypeInfoResolver统一覆盖 + Configure(options => { - builder - .WithOrigins( - configuration["App:CorsOrigins"]! - .Split(";", StringSplitOptions.RemoveEmptyEntries) - .Select(o => o.RemovePostFix("/")) - .ToArray() - ) - .WithAbpExposedHeaders() - .SetIsOriginAllowedToAllowWildcardSubdomains() - .AllowAnyHeader() - .AllowAnyMethod() - .AllowCredentials(); + options.JsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver(); + options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter()); + options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter()); }); - }); - //配置多租户 - 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); - }); - - //速率限制 - //每60秒限制100个请求,滑块添加,分6段 - service.AddRateLimiter(_ => - { - _.RejectionStatusCode = StatusCodes.Status429TooManyRequests; - _.OnRejected = (context, _) => + //设置缓存不要过期,默认滑动20分钟 + Configure(cacheOptions => { - if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) + 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 => { - context.HttpContext.Response.Headers.RetryAfter = - ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); + 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)); } - - 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 => + else { - var userAgent = httpContext.Request.Headers.UserAgent.ToString(); + config.UseMemoryStorage(); + } + }); - 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 => + //速率限制 + //每60秒限制100个请求,滑块添加,分6段 + service.AddRateLimiter(_ => { - options.TokenValidationParameters = new TokenValidationParameters + _.RejectionStatusCode = StatusCodes.Status429TooManyRequests; + _.OnRejected = (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 => + if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) { - var accessToken = context.Request.Query["access_token"]; - if (!string.IsNullOrEmpty(accessToken)) - { - context.Token = accessToken; - } - - return Task.CompletedTask; + context.HttpContext.Response.Headers.RetryAfter = + ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); } + + context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; + context.HttpContext.Response.WriteAsync("Too many requests. Please try again later."); + + return new ValueTask(); }; - }) - .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 => + + //全局使用,链式表达式 + _.GlobalLimiter = PartitionedRateLimiter.CreateChained( + PartitionedRateLimiter.Create(httpContext => { - var refresh_token = context.Request.Headers["refresh_token"]; - if (!string.IsNullOrEmpty(refresh_token)) + 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)) + }; + options.Events = new JwtBearerEvents + { + OnMessageReceived = context => { - context.Token = refresh_token; + var accessToken = context.Request.Query["access_token"]; + if (!string.IsNullOrEmpty(accessToken)) + { + context.Token = accessToken; + } + return Task.CompletedTask; } - - var refreshToken = context.Request.Query["refresh_token"]; - if (!string.IsNullOrEmpty(refreshToken)) + }; + }) + .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 => { - context.Token = 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; } + }; + }) + .AddQQ(options => { configuration.GetSection("OAuth:QQ").Bind(options); }) + .AddGitee(options => { configuration.GetSection("OAuth:Gitee").Bind(options); }); - return Task.CompletedTask; - } - }; - }) - .AddQQ(options => { configuration.GetSection("OAuth:QQ").Bind(options); }) - .AddGitee(options => { configuration.GetSection("OAuth:Gitee").Bind(options); }); + //授权 + context.Services.AddAuthorization(); - //授权 - context.Services.AddAuthorization(); - - return Task.CompletedTask; - } + + + return Task.CompletedTask; + } - public override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context) { var service = context.ServiceProvider; var env = context.GetEnvironment(); @@ -349,11 +382,15 @@ namespace Yi.Abp.Web //日志记录 app.UseAbpSerilogEnrichers(); + + //Hangfire定时任务面板,可配置授权 + app.UseAbpHangfireDashboard("/hangfire", options => + { + // options.AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter() }; + }); //终节点 app.UseConfiguredEndpoints(); - - return Task.CompletedTask; } } } \ No newline at end of file diff --git a/Yi.Abp.Net8/test/Yi.Framework.Rbac.Test/YiFrameworkRbacTestModule.cs b/Yi.Abp.Net8/test/Yi.Framework.Rbac.Test/YiFrameworkRbacTestModule.cs index 956492f6..40353e03 100644 --- a/Yi.Abp.Net8/test/Yi.Framework.Rbac.Test/YiFrameworkRbacTestModule.cs +++ b/Yi.Abp.Net8/test/Yi.Framework.Rbac.Test/YiFrameworkRbacTestModule.cs @@ -2,8 +2,6 @@ using Volo.Abp.Auditing; using Volo.Abp.Autofac; using Volo.Abp.BackgroundWorkers; -using Volo.Abp.BackgroundWorkers.Quartz; -using Volo.Abp.Domain.Repositories; using Yi.Framework.Rbac.Application; using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.Rbac.Domain.Managers; @@ -24,10 +22,11 @@ namespace Yi.Framework.Rbac.Test { public override void ConfigureServices(ServiceConfigurationContext context) { - Configure(options => - { - options.IsAutoRegisterEnabled = false; - }); + + // Configure(options => + // { + // options.IsAutoRegisterEnabled = false; + // }); Configure (options => { options.IsEnabled = false; //禁用作业执行 @@ -35,7 +34,6 @@ namespace Yi.Framework.Rbac.Test Configure(options => { options.Url = $"DataSource=yi-rbac-test-{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.db"; - }); }