Merge branch 'refs/heads/abp' into digital-collectibles

# Conflicts:
#	Yi.Abp.Net8/Yi.Abp.sln
#	Yi.Abp.Net8/module/bbs/Yi.Framework.Bbs.Application/Jobs/AccessLogCacheJob.cs
#	Yi.Abp.Net8/src/Yi.Abp.Application/Jobs/DemoResetJob.cs
#	Yi.Abp.Net8/src/Yi.Abp.Web/YiAbpWebModule.cs
This commit is contained in:
橙子
2024-11-15 20:16:23 +08:00
21 changed files with 422 additions and 459 deletions

View File

@@ -170,6 +170,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollect
EndProject 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}" 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 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 Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -504,6 +510,7 @@ Global
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C} {FFEC9DA6-1A13-480A-AE9E-2BF8763D3061} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F} = {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} {81CEA2ED-917B-41D8-BE0D-39A785B050C0} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
{862CA181-BEE6-4870-82D2-B662E527ED8C} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
EndGlobalSection EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18} SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18}

View File

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\common.props" />
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.BackgroundWorkers.Hangfire" Version="$(AbpVersion)" />
</ItemGroup>
</Project>

View File

@@ -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<IBackgroundWorkerManager>();
var works = context.ServiceProvider.GetServices<IHangfireBackgroundWorker>();
foreach (var work in works)
{
await backgroundWorkerManager.AddAsync(work);
}
}
}

View File

@@ -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<Type> GetExposedServiceTypes(Type type)
{
return new List<Type>()
{
typeof(IHangfireBackgroundWorker)
};
}
}

View File

@@ -1,8 +1,8 @@
using FreeRedis; using FreeRedis;
using Hangfire;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.Caching; using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
@@ -15,23 +15,27 @@ using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Application.Jobs; namespace Yi.Framework.Bbs.Application.Jobs;
public class AccessLogCacheJob : QuartzBackgroundWorkerBase public class AccessLogCacheJob : HangfireBackgroundWorkerBase
{ {
private readonly ILocalEventBus _localEventBus; private readonly ILocalEventBus _localEventBus;
public AccessLogCacheJob(ILocalEventBus localEventBus) public AccessLogCacheJob(ILocalEventBus localEventBus)
{ {
_localEventBus = localEventBus; _localEventBus = localEventBus;
JobDetail = JobBuilder.Create<AccessLogCacheJob>().WithIdentity(nameof(AccessLogCacheJob)) RecurringJobId = "访问日志写入缓存";
.Build(); //每10秒执行一次将本地缓存转入redis防止丢数据
CronExpression = "*/10 * * * * *";
//
// JobDetail = JobBuilder.Create<AccessLogCacheJob>().WithIdentity(nameof(AccessLogCacheJob))
// .Build();
//每10秒执行一次将本地缓存转入redis防止丢数据 //每10秒执行一次将本地缓存转入redis防止丢数据
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogCacheJob)) // Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogCacheJob))
.WithSimpleSchedule((schedule) => { schedule.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever(); }) // .WithSimpleSchedule((schedule) => { schedule.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever();; })
.Build(); // .Build();
} }
public override async Task Execute(IJobExecutionContext context) public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
await _localEventBus.PublishAsync(new AccessLogResetArgs()); await _localEventBus.PublishAsync(new AccessLogResetArgs());
} }

View File

@@ -1,11 +1,9 @@
using FreeRedis; using FreeRedis;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.Caching; using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities;
using Yi.Framework.Bbs.Domain.Entities; using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Shared.Caches; using Yi.Framework.Bbs.Domain.Shared.Caches;
using Yi.Framework.Bbs.Domain.Shared.Enums; using Yi.Framework.Bbs.Domain.Shared.Enums;
@@ -13,7 +11,7 @@ using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Application.Jobs; namespace Yi.Framework.Bbs.Application.Jobs;
public class AccessLogStoreJob : QuartzBackgroundWorkerBase public class AccessLogStoreJob : HangfireBackgroundWorkerBase
{ {
private readonly ISqlSugarRepository<AccessLogAggregateRoot> _repository; private readonly ISqlSugarRepository<AccessLogAggregateRoot> _repository;
@@ -45,18 +43,23 @@ public class AccessLogStoreJob : QuartzBackgroundWorkerBase
public AccessLogStoreJob(ISqlSugarRepository<AccessLogAggregateRoot> repository) public AccessLogStoreJob(ISqlSugarRepository<AccessLogAggregateRoot> repository)
{ {
_repository = repository; _repository = repository;
JobDetail = JobBuilder.Create<AccessLogStoreJob>().WithIdentity(nameof(AccessLogStoreJob))
.Build();
RecurringJobId = "访问日志写入数据库";
//每分钟执行一次 //每分钟执行一次
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AccessLogStoreJob)) CronExpression = "0 * * * * ?";
.WithCronSchedule("0 * * * * ?") // JobDetail = JobBuilder.Create<AccessLogStoreJob>().WithIdentity(nameof(AccessLogStoreJob))
.Build(); // .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) if (EnableRedisCache)
{ {

View File

@@ -1,5 +1,4 @@
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.BackgroundWorkers.Quartz;
using Yi.Framework.Bbs.Domain.Managers; using Yi.Framework.Bbs.Domain.Managers;
namespace Yi.Framework.Bbs.Application.Jobs; namespace Yi.Framework.Bbs.Application.Jobs;
@@ -7,20 +6,25 @@ namespace Yi.Framework.Bbs.Application.Jobs;
/// <summary> /// <summary>
/// 每日任务job /// 每日任务job
/// </summary> /// </summary>
public class AssignmentExpireTimeOutJob : QuartzBackgroundWorkerBase public class AssignmentExpireTimeOutJob : HangfireBackgroundWorkerBase
{ {
private readonly AssignmentManager _assignmentManager; private readonly AssignmentManager _assignmentManager;
public AssignmentExpireTimeOutJob(AssignmentManager assignmentManager) public AssignmentExpireTimeOutJob(AssignmentManager assignmentManager)
{ {
_assignmentManager = assignmentManager; _assignmentManager = assignmentManager;
JobDetail = JobBuilder.Create<AssignmentExpireTimeOutJob>().WithIdentity(nameof(AssignmentExpireTimeOutJob)).Build();
//每个小时整点执行一次 RecurringJobId = "每日任务系统超时检测";
Trigger = TriggerBuilder.Create().WithIdentity(nameof(AssignmentExpireTimeOutJob)).WithCronSchedule("0 0 * * * ?") //每分钟执行一次
.Build(); CronExpression = "0 * * * * ?";
//
// JobDetail = JobBuilder.Create<AssignmentExpireTimeOutJob>().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(); await _assignmentManager.ExpireTimeoutAsync();
} }

View File

@@ -1,20 +1,24 @@
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.BackgroundWorkers.Quartz;
using Yi.Framework.Bbs.Domain.Managers; using Yi.Framework.Bbs.Domain.Managers;
namespace Yi.Framework.Bbs.Application.Jobs namespace Yi.Framework.Bbs.Application.Jobs
{ {
public class InterestRecordsJob : QuartzBackgroundWorkerBase public class InterestRecordsJob : HangfireBackgroundWorkerBase
{ {
private BankManager _bankManager; private BankManager _bankManager;
public InterestRecordsJob(BankManager bankManager) public InterestRecordsJob(BankManager bankManager)
{ {
_bankManager = bankManager; _bankManager = bankManager;
JobDetail = JobBuilder.Create<InterestRecordsJob>().WithIdentity(nameof(InterestRecordsJob)).Build();
RecurringJobId = "银行利息积分刷新";
//每个小时整点执行一次 //每个小时整点执行一次
CronExpression = "0 0 * * * ?";
Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).WithCronSchedule("0 0 * * * ?").Build();
// JobDetail = JobBuilder.Create<InterestRecordsJob>().WithIdentity(nameof(InterestRecordsJob)).Build();
//
// //每个小时整点执行一次
//
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)).WithCronSchedule("0 0 * * * ?").Build();
//测试 //测试
// Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob)) // Trigger = TriggerBuilder.Create().WithIdentity(nameof(InterestRecordsJob))
@@ -23,7 +27,8 @@ namespace Yi.Framework.Bbs.Application.Jobs
// .RepeatForever()) // .RepeatForever())
//.Build(); //.Build();
} }
public override async Task Execute(IJobExecutionContext context)
public override async Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
//创建一个记录,莫得了 //创建一个记录,莫得了
await _bankManager.GetCurrentInterestRate(); await _bankManager.GetCurrentInterestRate();

View File

@@ -27,13 +27,19 @@ namespace Yi.Framework.Bbs.Application.Services
var userEntity = await _bbsUserManager._userRepository.GetFirstAsync(x => x.UserName == userNameOrUserId); var userEntity = await _bbsUserManager._userRepository.GetFirstAsync(x => x.UserName == userNameOrUserId);
if (userEntity == null) if (userEntity == null)
{ {
throw new Volo.Abp.UserFriendlyException("该用户不存在"); throw new UserFriendlyException("该用户不存在");
} }
userId= userEntity.Id; userId= userEntity.Id;
} }
var output =await _bbsUserManager.GetBbsUserInfoAsync(userId); var output =await _bbsUserManager.GetBbsUserInfoAsync(userId);
//不是自己
if (CurrentUser.Id != output.Id)
{
output.Phone = null;
output.Email=null;
}
return output!; return output!;
} }
} }

View File

@@ -136,6 +136,11 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
[Authorize] [Authorize]
public override async Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input) public override async Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input)
{ {
if (input.Content.Length<=6)
{
throw new UserFriendlyException("评论长度至少大于6");
}
var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId); var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId);
if (discuess is null) if (discuess is null)
{ {

View File

@@ -6,16 +6,14 @@ using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Quartz.Logging;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Yi.Framework.Rbac.Domain.Shared.Options; using Yi.Framework.Rbac.Domain.Shared.Options;
using Yi.Framework.SqlSugarCore.Abstractions; using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Rbac.Application.Jobs namespace Yi.Framework.Rbac.Application.Jobs
{ {
public class BackupDataBaseJob : QuartzBackgroundWorkerBase public class BackupDataBaseJob: HangfireBackgroundWorkerBase
{ {
private ISqlSugarDbContext _dbContext; private ISqlSugarDbContext _dbContext;
private IOptions<RbacOptions> _options; private IOptions<RbacOptions> _options;
@@ -24,13 +22,12 @@ namespace Yi.Framework.Rbac.Application.Jobs
_options = options; _options = options;
_dbContext = dbContext; _dbContext = dbContext;
JobDetail = JobBuilder.Create<BackupDataBaseJob>().WithIdentity(nameof(BackupDataBaseJob)).Build();
RecurringJobId = "数据库备份";
//每天00点与24点进行备份 //每天00点与24点进行备份
Trigger = TriggerBuilder.Create().WithIdentity(nameof(BackupDataBaseJob)).WithCronSchedule("0 0 0,12 * * ? ").Build(); CronExpression = "0 0 0,12 * * ? ";
//Trigger = TriggerBuilder.Create().WithIdentity(nameof(BackupDataBaseJob)).WithSimpleSchedule(x=>x.WithIntervalInSeconds(10)).Build();
} }
public override Task Execute(IJobExecutionContext context) public override Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
if (_options.Value.EnableDataBaseBackup) if (_options.Value.EnableDataBaseBackup)
{ {

View File

@@ -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;
}
/// <summary>
/// 单查job
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
[HttpGet("task/{jobId}")]
public async Task<TaskGetOutput> 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;
}
/// <summary>
/// 多查job
/// </summary>
/// <returns></returns>
public async Task<PagedResultDto<TaskGetListOutput>> GetListAsync([FromQuery] TaskGetListInput input)
{
var items = new List<TaskGetOutput>();
var scheduler = await _schedulerFactory.GetScheduler();
var groups = await scheduler.GetJobGroupNames();
foreach (var groupName in groups)
{
foreach (var jobKey in await scheduler.GetJobKeys(GroupMatcher<JobKey>.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<TaskGetListOutput>(items.Count(), output.Adapt<List<TaskGetListOutput>>());
}
/// <summary>
/// 创建job
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
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());
}
/// <summary>
/// 移除job
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task DeleteAsync(IEnumerable<string> id)
{
var scheduler = await _schedulerFactory.GetScheduler();
await scheduler.DeleteJobs(id.Select(x => new JobKey(x)).ToList());
}
/// <summary>
/// 暂停job
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
[HttpPut]
public async Task PauseAsync(string jobId)
{
var scheduler = await _schedulerFactory.GetScheduler();
await scheduler.PauseJob(new JobKey(jobId));
}
/// <summary>
/// 开始job
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
[HttpPut]
public async Task StartAsync(string jobId)
{
var scheduler = await _schedulerFactory.GetScheduler();
await scheduler.ResumeJob(new JobKey(jobId));
}
/// <summary>
/// 更新job
/// </summary>
/// <param name="id"></param>
/// <param name="input"></param>
/// <returns></returns>
public async Task UpdateAsync(string id, TaskUpdateInput input)
{
await DeleteAsync(new List<string>() { id });
await CreateAsync(input.Adapt<TaskCreateInput>());
}
[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);
}
}
}

View File

@@ -10,13 +10,15 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Lazy.Captcha.Core" Version="2.0.7" /> <PackageReference Include="Lazy.Captcha.Core" Version="2.0.7" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" /> <PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.7" />
<PackageReference Include="Volo.Abp.BackgroundWorkers.Quartz" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.BackgroundJobs.Hangfire" Version="$(AbpVersion)" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" /> <ProjectReference Include="..\..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" />
<ProjectReference Include="..\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj" /> <ProjectReference Include="..\Yi.Framework.Rbac.Application.Contracts\Yi.Framework.Rbac.Application.Contracts.csproj" />
<ProjectReference Include="..\Yi.Framework.Rbac.Domain\Yi.Framework.Rbac.Domain.csproj" /> <ProjectReference Include="..\Yi.Framework.Rbac.Domain\Yi.Framework.Rbac.Domain.csproj" />
<ProjectReference Include="..\..\..\framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -2,7 +2,7 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.BackgroundWorkers; using Volo.Abp.BackgroundWorkers;
using Volo.Abp.BackgroundWorkers.Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Yi.Framework.Ddd.Application; using Yi.Framework.Ddd.Application;
using Yi.Framework.Rbac.Application.Contracts; using Yi.Framework.Rbac.Application.Contracts;
@@ -16,8 +16,7 @@ namespace Yi.Framework.Rbac.Application
typeof(YiFrameworkRbacDomainModule), typeof(YiFrameworkRbacDomainModule),
typeof(YiFrameworkDddApplicationModule), typeof(YiFrameworkDddApplicationModule)
typeof(AbpBackgroundWorkersQuartzModule)
)] )]
public class YiFrameworkRbacApplicationModule : AbpModule public class YiFrameworkRbacApplicationModule : AbpModule
{ {
@@ -28,7 +27,6 @@ namespace Yi.Framework.Rbac.Application
service.AddCaptcha(options => service.AddCaptcha(options =>
{ {
options.CaptchaType = CaptchaType.ARITHMETIC; options.CaptchaType = CaptchaType.ARITHMETIC;
}); });
} }

View File

@@ -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<DemoResetJob> _logger => LoggerFactory.CreateLogger<DemoResetJob>();
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<bool>())
{
//定时任务,非常简单
_logger.LogWarning("演示环境正在还原!");
var db = _dbContext.SqlSugarClient.CopyNew();
db.DbMaintenance.TruncateTable<UserAggregateRoot>();
db.DbMaintenance.TruncateTable<UserRoleEntity>();
db.DbMaintenance.TruncateTable<RoleAggregateRoot>();
db.DbMaintenance.TruncateTable<RoleMenuEntity>();
db.DbMaintenance.TruncateTable<MenuAggregateRoot>();
db.DbMaintenance.TruncateTable<RoleDeptEntity>();
db.DbMaintenance.TruncateTable<DeptAggregateRoot>();
db.DbMaintenance.TruncateTable<PostAggregateRoot>();
db.DbMaintenance.TruncateTable<UserPostEntity>();
//删除种子数据
await _dataSeeder.SeedAsync();
_logger.LogWarning("演示环境还原成功!");
}
}
}
}

View File

@@ -1,6 +1,6 @@
using Quartz; using Hangfire;
using SqlSugar; using SqlSugar;
using Volo.Abp.BackgroundWorkers.Quartz; using Volo.Abp.BackgroundWorkers.Hangfire;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Uow; using Volo.Abp.Uow;
using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.Rbac.Domain.Entities;
@@ -11,26 +11,21 @@ namespace Yi.Abp.Application.Jobs
/// <summary> /// <summary>
/// 定时任务 /// 定时任务
/// </summary> /// </summary>
public class TestJob : QuartzBackgroundWorkerBase public class TestJob : HangfireBackgroundWorkerBase
{ {
private ISqlSugarRepository<UserAggregateRoot> _repository; private ISqlSugarRepository<UserAggregateRoot> _repository;
public TestJob(ISqlSugarRepository<UserAggregateRoot> repository) public TestJob(ISqlSugarRepository<UserAggregateRoot> repository)
{ {
_repository = repository; _repository = repository;
JobDetail = JobBuilder.Create<TestJob>().WithIdentity(nameof(TestJob)).Build(); RecurringJobId = "测试";
Trigger = TriggerBuilder.Create().WithIdentity(nameof(TestJob)).StartNow() //每天一次
.WithSimpleSchedule(x => x CronExpression = Cron.Daily();
.WithIntervalInSeconds(1000 * 60)
.RepeatForever())
.Build();
} }
public override async Task Execute(IJobExecutionContext context) public override Task DoWorkAsync(CancellationToken cancellationToken = new CancellationToken())
{ {
//定时任务,非常简单 //定时任务,非常简单
Console.WriteLine("你好,世界"); Console.WriteLine("你好,世界");
// var eneities= await _repository.GetListAsync(); return Task.CompletedTask;
//var entities= await _sqlSugarClient.Queryable<UserEntity>().ToListAsync();
//await Console.Out.WriteLineAsync(entities.Count().ToString());
} }
} }
} }

View File

@@ -3,6 +3,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\framework\Yi.Framework.BackgroundWorkers.Hangfire\Yi.Framework.BackgroundWorkers.Hangfire.csproj" />
<ProjectReference Include="..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" /> <ProjectReference Include="..\..\framework\Yi.Framework.Ddd.Application\Yi.Framework.Ddd.Application.csproj" />
<ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.Application\Yi.Framework.Bbs.Application.csproj" /> <ProjectReference Include="..\..\module\bbs\Yi.Framework.Bbs.Application\Yi.Framework.Bbs.Application.csproj" />
<ProjectReference Include="..\..\module\chat-hub\Yi.Framework.ChatHub.Application\Yi.Framework.ChatHub.Application.csproj" /> <ProjectReference Include="..\..\module\chat-hub\Yi.Framework.ChatHub.Application\Yi.Framework.ChatHub.Application.csproj" />

View File

@@ -1,6 +1,7 @@
using Volo.Abp.SettingManagement; using Volo.Abp.SettingManagement;
using Yi.Abp.Application.Contracts; using Yi.Abp.Application.Contracts;
using Yi.Abp.Domain; using Yi.Abp.Domain;
using Yi.Framework.BackgroundWorkers.Hangfire;
using Yi.Framework.Bbs.Application; using Yi.Framework.Bbs.Application;
using Yi.Framework.ChatHub.Application; using Yi.Framework.ChatHub.Application;
using Yi.Framework.CodeGen.Application; using Yi.Framework.CodeGen.Application;
@@ -25,7 +26,8 @@ namespace Yi.Abp.Application
typeof(YiFrameworkCodeGenApplicationModule), typeof(YiFrameworkCodeGenApplicationModule),
typeof (YiFrameworkSettingManagementApplicationModule), typeof (YiFrameworkSettingManagementApplicationModule),
typeof(YiFrameworkDddApplicationModule) typeof(YiFrameworkDddApplicationModule),
typeof(YiFrameworkBackgroundWorkersHangfireModule)
)] )]
public class YiAbpApplicationModule : AbpModule public class YiAbpApplicationModule : AbpModule
{ {

View File

@@ -8,6 +8,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Hangfire.MemoryStorage" Version="1.8.1.1" />
<PackageReference Include="Hangfire.Redis.StackExchange" Version="1.9.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.3" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.3" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.3" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" /> <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.6" />

View File

@@ -3,6 +3,9 @@ using System.Text;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata; using System.Text.Json.Serialization.Metadata;
using System.Threading.RateLimiting; using System.Threading.RateLimiting;
using Hangfire;
using Hangfire.MemoryStorage;
using Hangfire.Redis.StackExchange;
using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -12,20 +15,21 @@ using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens; using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models; 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.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.ExceptionHandling; using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.AspNetCore.MultiTenancy; using Volo.Abp.AspNetCore.MultiTenancy;
using Volo.Abp.AspNetCore.Mvc; using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.AspNetCore.Mvc.AntiForgery; using Volo.Abp.AspNetCore.Mvc.AntiForgery;
using Volo.Abp.AspNetCore.Mvc.ExceptionHandling;
using Volo.Abp.AspNetCore.Serilog; using Volo.Abp.AspNetCore.Serilog;
using Volo.Abp.AspNetCore.VirtualFileSystem; using Volo.Abp.AspNetCore.VirtualFileSystem;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Autofac; 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.Caching;
using Volo.Abp.Json;
using Volo.Abp.Json.SystemTextJson;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Swashbuckle; using Volo.Abp.Swashbuckle;
using Yi.Abp.Application; 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.Authentication.OAuth.QQ;
using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder; using Yi.Framework.AspNetCore.Microsoft.AspNetCore.Builder;
using Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection; 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;
using Yi.Framework.Bbs.Application.Extensions; using Yi.Framework.Bbs.Application.Extensions;
using Yi.Framework.ChatHub.Application; using Yi.Framework.ChatHub.Application;
@@ -60,6 +64,8 @@ namespace Yi.Abp.Web
typeof(AbpSwashbuckleModule), typeof(AbpSwashbuckleModule),
typeof(AbpAspNetCoreSerilogModule), typeof(AbpAspNetCoreSerilogModule),
typeof(AbpAuditingModule), typeof(AbpAuditingModule),
typeof(YiFrameworkBackgroundWorkersHangfireModule),
typeof(AbpBackgroundJobsHangfireModule),
typeof(AbpAspNetCoreAuthenticationJwtBearerModule), typeof(AbpAspNetCoreAuthenticationJwtBearerModule),
typeof(YiFrameworkAspNetCoreModule), typeof(YiFrameworkAspNetCoreModule),
typeof(YiFrameworkAspNetCoreAuthenticationOAuthModule) typeof(YiFrameworkAspNetCoreAuthenticationOAuthModule)
@@ -73,21 +79,26 @@ namespace Yi.Abp.Web
var configuration = context.Services.GetConfiguration(); var configuration = context.Services.GetConfiguration();
var host = context.Services.GetHostingEnvironment(); var host = context.Services.GetHostingEnvironment();
var service = context.Services; var service = context.Services;
//请求日志 //请求日志
Configure<AbpAuditingOptions>(optios => Configure<AbpAuditingOptions>(optios =>
{ {
//默认关闭,开启会有大量的审计日志 //默认关闭,开启会有大量的审计日志
optios.IsEnabled = true; optios.IsEnabled = true;
//审计日志过滤器,符合条件的才记录
optios.AlwaysLogSelectors.Add(x => Task.FromResult(x.Url is null?true:!x.Url.StartsWith("/api/app/file/")));
}); });
//忽略审计日志路径
Configure<AbpAspNetCoreAuditingOptions>(options =>
{
options.IgnoredUrls.Add("/api/app/file/");
options.IgnoredUrls.Add("/hangfire");
});
//采用furion格式的规范化api默认不开启使用abp优雅的方式 //采用furion格式的规范化api默认不开启使用abp优雅的方式
//你没看错。。。 //你没看错。。。
//service.AddFurionUnifyResultApi(); //service.AddFurionUnifyResultApi();
//配置错误处理显示详情 //配置错误处理显示详情
Configure<AbpExceptionHandlingOptions>(options => { options.SendExceptionsDetailsToClients = true; }); Configure<AbpExceptionHandlingOptions>(options => { options.SendExceptionsDetailsToClients = true; });
//动态Api //动态Api
Configure<AbpAspNetCoreMvcOptions>(options => Configure<AbpAspNetCoreMvcOptions>(options =>
@@ -110,181 +121,203 @@ namespace Yi.Abp.Web
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app"); options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
}); });
//【NewtonsoftJson严重问题逆天】设置api格式留给后人铭记 //【NewtonsoftJson严重问题逆天】设置api格式留给后人铭记
// service.AddControllers().AddNewtonsoftJson(options => // service.AddControllers().AddNewtonsoftJson(options =>
// { // {
// options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; // options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
// options.SerializerSettings.Converters.Add(new StringEnumConverter()); // options.SerializerSettings.Converters.Add(new StringEnumConverter());
// }); // });
//请使用微软的注意abp date又包了一层采用DefaultJsonTypeInfoResolver统一覆盖
Configure<JsonOptions>(options =>
{
options.JsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
});
//设置缓存不要过期默认滑动20分钟 //请使用微软的注意abp date又包了一层采用DefaultJsonTypeInfoResolver统一覆盖
Configure<AbpDistributedCacheOptions>(cacheOptions => Configure<JsonOptions>(options =>
{
cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null;
//缓存key前缀
cacheOptions.KeyPrefix = "Yi:";
});
Configure<AbpAntiForgeryOptions>(options => { options.AutoValidate = false; });
//Swagger
context.Services.AddYiSwaggerGen<YiAbpWebModule>(options =>
{
options.SwaggerDoc("default",
new OpenApiInfo { Title = "Yi.Framework.Abp", Version = "v1", Description = "集大成者" });
});
//跨域
context.Services.AddCors(options =>
{
options.AddPolicy(DefaultCorsPolicyName, builder =>
{ {
builder options.JsonSerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver();
.WithOrigins( options.JsonSerializerOptions.Converters.Add(new DatetimeJsonConverter());
configuration["App:CorsOrigins"]! options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
.Split(";", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.WithAbpExposedHeaders()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
}); });
});
//配置多租户 //设置缓存不要过期默认滑动20分钟
Configure<AbpTenantResolveOptions>(options => Configure<AbpDistributedCacheOptions>(cacheOptions =>
{
//基于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, _) =>
{ {
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter)) cacheOptions.GlobalCacheEntryOptions.SlidingExpiration = null;
//缓存key前缀
cacheOptions.KeyPrefix = "Yi:";
});
Configure<AbpAntiForgeryOptions>(options => { options.AutoValidate = false; });
//Swagger
context.Services.AddYiSwaggerGen<YiAbpWebModule>(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 = builder
((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo); .WithOrigins(
configuration["App:CorsOrigins"]!
.Split(";", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.WithAbpExposedHeaders()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
//配置多租户
Configure<AbpTenantResolveOptions>(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
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, string>(httpContext =>
{ {
var userAgent = httpContext.Request.Headers.UserAgent.ToString(); config.UseMemoryStorage();
}
});
return RateLimitPartition.GetSlidingWindowLimiter //速率限制
(userAgent, _ => //每60秒限制100个请求滑块添加分6段
new SlidingWindowRateLimiterOptions service.AddRateLimiter(_ =>
{
PermitLimit = 1000,
Window = TimeSpan.FromSeconds(60),
SegmentsPerWindow = 6,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst
});
}));
});
//jwt鉴权
var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>();
var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get<RefreshJwtOptions>();
context.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{ {
options.TokenValidationParameters = new TokenValidationParameters _.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
_.OnRejected = (context, _) =>
{ {
ClockSkew = TimeSpan.Zero, if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
ValidateIssuerSigningKey = true,
ValidIssuer = jwtOptions.Issuer,
ValidAudience = jwtOptions.Audience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtOptions.SecurityKey))
};
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{ {
var accessToken = context.Request.Query["access_token"]; context.HttpContext.Response.Headers.RetryAfter =
if (!string.IsNullOrEmpty(accessToken)) ((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo);
{
context.Token = accessToken;
}
return Task.CompletedTask;
} }
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
context.HttpContext.Response.WriteAsync("Too many requests. Please try again later.");
return new ValueTask();
}; };
})
.AddJwtBearer(TokenTypeConst.Refresh, options => //全局使用,链式表达式
{ _.GlobalLimiter = PartitionedRateLimiter.CreateChained(
options.TokenValidationParameters = new TokenValidationParameters PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
{
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"]; var userAgent = httpContext.Request.Headers.UserAgent.ToString();
if (!string.IsNullOrEmpty(refresh_token))
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<JwtOptions>();
var refreshJwtOptions = configuration.GetSection(nameof(RefreshJwtOptions)).Get<RefreshJwtOptions>();
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; 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; //授权
} context.Services.AddAuthorization();
};
})
.AddQQ(options => { configuration.GetSection("OAuth:QQ").Bind(options); })
.AddGitee(options => { configuration.GetSection("OAuth:Gitee").Bind(options); });
//授权
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 service = context.ServiceProvider;
var env = context.GetEnvironment(); var env = context.GetEnvironment();
@@ -349,11 +382,15 @@ namespace Yi.Abp.Web
//日志记录 //日志记录
app.UseAbpSerilogEnrichers(); app.UseAbpSerilogEnrichers();
//Hangfire定时任务面板可配置授权
app.UseAbpHangfireDashboard("/hangfire", options =>
{
// options.AsyncAuthorization = new[] { new AbpHangfireAuthorizationFilter() };
});
//终节点 //终节点
app.UseConfiguredEndpoints(); app.UseConfiguredEndpoints();
return Task.CompletedTask;
} }
} }
} }

View File

@@ -2,8 +2,6 @@
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Autofac; using Volo.Abp.Autofac;
using Volo.Abp.BackgroundWorkers; using Volo.Abp.BackgroundWorkers;
using Volo.Abp.BackgroundWorkers.Quartz;
using Volo.Abp.Domain.Repositories;
using Yi.Framework.Rbac.Application; using Yi.Framework.Rbac.Application;
using Yi.Framework.Rbac.Domain.Entities; using Yi.Framework.Rbac.Domain.Entities;
using Yi.Framework.Rbac.Domain.Managers; using Yi.Framework.Rbac.Domain.Managers;
@@ -24,10 +22,11 @@ namespace Yi.Framework.Rbac.Test
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
Configure<AbpBackgroundWorkerQuartzOptions>(options =>
{ // Configure<AbpBackgroundWorkerQuartzOptions>(options =>
options.IsAutoRegisterEnabled = false; // {
}); // options.IsAutoRegisterEnabled = false;
// });
Configure<AbpBackgroundWorkerOptions> (options => Configure<AbpBackgroundWorkerOptions> (options =>
{ {
options.IsEnabled = false; //禁用作业执行 options.IsEnabled = false; //禁用作业执行
@@ -35,7 +34,6 @@ namespace Yi.Framework.Rbac.Test
Configure<DbConnOptions>(options => Configure<DbConnOptions>(options =>
{ {
options.Url = $"DataSource=yi-rbac-test-{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.db"; options.Url = $"DataSource=yi-rbac-test-{DateTime.Now.ToString("yyyyMMdd_HHmmss")}.db";
}); });
} }