From eb5c79b16cff12006a3137c9686940e8159cef62 Mon Sep 17 00:00:00 2001 From: maliming Date: Sun, 3 Apr 2022 20:46:19 +0800 Subject: [PATCH] Add `TokenCleanupBackgroundWorker`. --- .../OpenIddict/AbpOpenIddictDomainModule.cs | 22 +++++- .../Tokens/TokenCleanupBackgroundWorker.cs | 27 ++++++++ .../OpenIddict/Tokens/TokenCleanupOptions.cs | 41 +++++++++++ .../OpenIddict/Tokens/TokenCleanupService.cs | 68 +++++++++++++++++++ 4 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupBackgroundWorker.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupOptions.cs create mode 100644 modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupService.cs diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/AbpOpenIddictDomainModule.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/AbpOpenIddictDomainModule.cs index fea900830f..345392fffa 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/AbpOpenIddictDomainModule.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/AbpOpenIddictDomainModule.cs @@ -1,6 +1,9 @@ -using Microsoft.Extensions.DependencyInjection; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using OpenIddict.Abstractions; using OpenIddict.Core; +using Volo.Abp.BackgroundWorkers; using Volo.Abp.Domain; using Volo.Abp.Identity; using Volo.Abp.Modularity; @@ -9,6 +12,7 @@ using Volo.Abp.OpenIddict.Authorizations; using Volo.Abp.OpenIddict.Scopes; using Volo.Abp.OpenIddict.Tokens; using Volo.Abp.Security.Claims; +using Volo.Abp.Threading; namespace Volo.Abp.OpenIddict; @@ -24,6 +28,22 @@ public class AbpOpenIddictDomainModule : AbpModule AddOpenIddict(context.Services); } + public override void OnApplicationInitialization(ApplicationInitializationContext context) + { + AsyncHelper.RunSync(() => OnApplicationInitializationAsync(context)); + } + + public async override Task OnApplicationInitializationAsync(ApplicationInitializationContext context) + { + var options = context.ServiceProvider.GetRequiredService>().Value; + if (options.IsCleanupEnabled) + { + await context.ServiceProvider + .GetRequiredService() + .AddAsync(context.ServiceProvider.GetRequiredService()); + } + } + private static void AddOpenIddict(IServiceCollection services) { var builderOptions = services.ExecutePreConfiguredActions(); diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupBackgroundWorker.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupBackgroundWorker.cs new file mode 100644 index 0000000000..c89ac256d0 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupBackgroundWorker.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.BackgroundWorkers; +using Volo.Abp.Threading; + +namespace Volo.Abp.OpenIddict.Tokens; + +public class TokenCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase +{ + public TokenCleanupBackgroundWorker( + AbpAsyncTimer timer, + IServiceScopeFactory serviceScopeFactory, + IOptionsMonitor cleanupOptions) + : base(timer, serviceScopeFactory) + { + timer.Period = cleanupOptions.CurrentValue.CleanupPeriod; + } + + protected async override Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext) + { + await workerContext + .ServiceProvider + .GetRequiredService() + .CleanAsync(); + } +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupOptions.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupOptions.cs new file mode 100644 index 0000000000..3b0ea3bfaa --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupOptions.cs @@ -0,0 +1,41 @@ +using System; +using Volo.Abp.BackgroundWorkers; + +namespace Volo.Abp.OpenIddict.Tokens; + +public class TokenCleanupOptions +{ + /// + /// Default value: true. + /// If is false, + /// this property is ignored and the cleanup worker doesn't work for this application instance. + /// + public bool IsCleanupEnabled { get; set; } = true; + + /// + /// Default: 3,600,000 ms. + /// + public int CleanupPeriod { get; set; } = 3_600_000; + + /// + /// Gets or sets a boolean indicating whether authorizations pruning should be disabled. + /// + public bool DisableAuthorizationPruning { get; set; } + + /// + /// Gets or sets a boolean indicating whether tokens pruning should be disabled. + /// + public bool DisableTokenPruning { get; set; } + + /// + /// Gets or sets the minimum lifespan authorizations must have to be pruned. + /// By default, this value is set to 14 days and cannot be less than 10 minutes. + /// + public TimeSpan MinimumAuthorizationLifespan { get; set; } = TimeSpan.FromDays(14); + + /// + /// Gets or sets the minimum lifespan tokens must have to be pruned. + /// By default, this value is set to 14 days and cannot be less than 10 minutes. + /// + public TimeSpan MinimumTokenLifespan { get; set; } = TimeSpan.FromDays(14); +} diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupService.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupService.cs new file mode 100644 index 0000000000..281ed5e4b1 --- /dev/null +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.Domain/Volo/Abp/OpenIddict/Tokens/TokenCleanupService.cs @@ -0,0 +1,68 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Logging.Abstractions; +using Microsoft.Extensions.Options; +using OpenIddict.Abstractions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.OpenIddict.Tokens; + +// Note: this background task is responsible of automatically removing orphaned tokens/authorizations +// (i.e tokens that are no longer valid and ad-hoc authorizations that have no valid tokens associated). +// Import: since tokens associated to ad-hoc authorizations are not removed as part of the same operation, +// the tokens MUST be deleted before removing the ad-hoc authorizations that no longer have any token. +public class TokenCleanupService : ITransientDependency +{ + public ILogger Logger { get; set; } + protected TokenCleanupOptions CleanupOptions { get; } + protected IOpenIddictTokenManager TokenManager { get; } + protected IOpenIddictAuthorizationManager AuthorizationManager { get; } + + public TokenCleanupService( + IOptionsMonitor cleanupOptions, + IOpenIddictTokenManager tokenManager, + IOpenIddictAuthorizationManager authorizationManager) + { + Logger = NullLogger.Instance;; + + CleanupOptions = cleanupOptions.CurrentValue; + TokenManager = tokenManager; + AuthorizationManager = authorizationManager; + } + + public virtual async Task CleanAsync() + { + Logger.LogInformation("Start cleanup."); + + if (!CleanupOptions.DisableTokenPruning) + { + Logger.LogInformation("Start cleanup tokens."); + + var threshold = DateTimeOffset.UtcNow - CleanupOptions.MinimumTokenLifespan; + try + { + await TokenManager.PruneAsync(threshold); + } + catch (Exception exception) + { + Logger.LogException(exception); + } + } + + if (!CleanupOptions.DisableAuthorizationPruning) + { + Logger.LogInformation("Start cleanup authorizations."); + + var threshold = DateTimeOffset.UtcNow - CleanupOptions.MinimumAuthorizationLifespan; + try + { + await AuthorizationManager.PruneAsync(threshold); + } + catch (Exception exception) + { + Logger.LogException(exception); + } + } + } +}