Implemented TokenCleanupService

pull/2545/head
Halil İbrahim Kalkan 5 years ago
parent 4ba4306165
commit c1f02ba066

@ -20,6 +20,7 @@
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Security\Volo.Abp.Security.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Caching\Volo.Abp.Caching.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Validation\Volo.Abp.Validation.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.BackgroundWorkers\Volo.Abp.BackgroundWorkers.csproj" />
</ItemGroup>
<ItemGroup>

@ -1,5 +1,4 @@
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Threading.Tasks;
using IdentityModel;
using IdentityServer4.Models;

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
@ -16,5 +17,11 @@ namespace Volo.Abp.IdentityServer.Devices
string deviceCode,
CancellationToken cancellationToken = default
);
Task<List<DeviceFlowCodes>> GetListByExpirationAsync(
DateTime maxExpirationDate,
int maxResultCount,
CancellationToken cancellationToken = default
);
}
}

@ -18,6 +18,12 @@ namespace Volo.Abp.IdentityServer.Grants
CancellationToken cancellationToken = default
);
Task<List<PersistedGrant>> GetListByExpirationAsync(
DateTime maxExpirationDate,
int maxResultCount,
CancellationToken cancellationToken = default
);
Task DeleteAsync(
string subjectId,
string clientId,

@ -0,0 +1,34 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Volo.Abp.BackgroundWorkers;
using Volo.Abp.Threading;
namespace Volo.Abp.IdentityServer.Tokens
{
public class TokenCleanupBackgroundWorker : AsyncPeriodicBackgroundWorkerBase
{
protected TokenCleanupOptions Options { get; }
public TokenCleanupBackgroundWorker(
AbpTimer timer,
IServiceScopeFactory serviceScopeFactory,
IOptions<TokenCleanupOptions> options)
: base(
timer,
serviceScopeFactory)
{
Options = options.Value;
timer.Period = Options.CleanupPeriod;
}
protected override async Task DoWorkAsync(PeriodicBackgroundWorkerContext workerContext)
{
await workerContext
.ServiceProvider
.GetRequiredService<TokenCleanupService>()
.CleanAsync()
.ConfigureAwait(false);
}
}
}

@ -0,0 +1,34 @@
using Volo.Abp.BackgroundWorkers;
namespace Volo.Abp.IdentityServer.Tokens
{
public class TokenCleanupOptions
{
/// <summary>
/// Default: 3,600,000 ms.
/// </summary>
public int CleanupPeriod { get; set; } = 3_600_000;
/// <summary>
/// Default value: 100.
/// </summary>
public int CleanupBatchSize { get; set; } = 100;
/// <summary>
/// The number of loop if there are
/// more than <see cref="CleanupBatchSize"/> tokens in the database.
/// So, if <see cref="CleanupLoopCount"/> is 10 and <see cref="CleanupBatchSize"/> is 100,
/// then the cleanup worker will clean 1,000 items in one <see cref="CleanupPeriod"/> at max.
///
/// Default value: 10.
/// </summary>
public int CleanupLoopCount { get; set; } = 10;
/// <summary>
/// Default value: true.
/// If <see cref="AbpBackgroundWorkerOptions.IsEnabled"/> is false,
/// this property is ignored and the cleanup worker doesn't work for this application instance.
/// </summary>
public bool EnableCleanup { get; set; } = true;
}
}

@ -0,0 +1,88 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Options;
using Volo.Abp.DependencyInjection;
using Volo.Abp.IdentityServer.Devices;
using Volo.Abp.IdentityServer.Grants;
using Volo.Abp.Timing;
using Volo.Abp.Uow;
namespace Volo.Abp.IdentityServer.Tokens
{
public class TokenCleanupService : ITransientDependency
{
protected IPersistentGrantRepository PersistentGrantRepository { get; }
protected IDeviceFlowCodesRepository DeviceFlowCodesRepository { get; }
protected IClock Clock { get; }
protected TokenCleanupOptions Options { get; }
public TokenCleanupService(
IPersistentGrantRepository persistentGrantRepository,
IDeviceFlowCodesRepository deviceFlowCodesRepository,
IClock clock,
IOptions<TokenCleanupOptions> options)
{
PersistentGrantRepository = persistentGrantRepository;
DeviceFlowCodesRepository = deviceFlowCodesRepository;
Clock = clock;
Options = options.Value;
}
public virtual async Task CleanAsync()
{
await RemoveGrantsAsync()
.ConfigureAwait(false);
await RemoveDeviceCodesAsync()
.ConfigureAwait(false);
}
[UnitOfWork]
protected virtual async Task RemoveGrantsAsync()
{
for (int i = 0; i < Options.CleanupLoopCount; i++)
{
var persistentGrants = await PersistentGrantRepository
.GetListByExpirationAsync(Clock.Now, Options.CleanupBatchSize)
.ConfigureAwait(false);
//TODO: Can be optimized if the repository implements the batch deletion
foreach (var persistentGrant in persistentGrants)
{
await PersistentGrantRepository
.DeleteAsync(persistentGrant)
.ConfigureAwait(false);
}
//No need to continue to query if it gets more than max items.
if (persistentGrants.Count < Options.CleanupBatchSize)
{
break;
}
}
}
protected virtual async Task RemoveDeviceCodesAsync()
{
for (int i = 0; i < Options.CleanupLoopCount; i++)
{
var deviceFlowCodeses = await DeviceFlowCodesRepository
.GetListByExpirationAsync(Clock.Now, Options.CleanupBatchSize)
.ConfigureAwait(false);
//TODO: Can be optimized if the repository implements the batch deletion
foreach (var deviceFlowCodes in deviceFlowCodeses)
{
await DeviceFlowCodesRepository
.DeleteAsync(deviceFlowCodes)
.ConfigureAwait(false);
}
//No need to continue to query if it gets more than max items.
if (deviceFlowCodeses.Count < Options.CleanupBatchSize)
{
break;
}
}
}
}
}

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
@ -34,5 +36,16 @@ namespace Volo.Abp.IdentityServer.Devices
.FirstOrDefaultAsync(d => d.DeviceCode == deviceCode, GetCancellationToken(cancellationToken))
.ConfigureAwait(false);
}
public async Task<List<DeviceFlowCodes>> GetListByExpirationAsync(DateTime maxExpirationDate, int maxResultCount,
CancellationToken cancellationToken = default)
{
return await DbSet
.Where(x => x.Expiration != null && x.Expiration < maxExpirationDate)
.OrderBy(x => x.ClientId)
.Take(maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken))
.ConfigureAwait(false);
}
}
}

@ -18,21 +18,36 @@ namespace Volo.Abp.IdentityServer.Grants
}
public Task<PersistedGrant> FindByKeyAsync(
public async Task<PersistedGrant> FindByKeyAsync(
string key,
CancellationToken cancellationToken = default)
{
return DbSet
.FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken));
return await DbSet
.FirstOrDefaultAsync(x => x.Key == key, GetCancellationToken(cancellationToken))
.ConfigureAwait(false);
}
public Task<List<PersistedGrant>> GetListBySubjectIdAsync(
public async Task<List<PersistedGrant>> GetListBySubjectIdAsync(
string subjectId,
CancellationToken cancellationToken = default)
{
return DbSet
return await DbSet
.Where(x => x.SubjectId == subjectId)
.ToListAsync(GetCancellationToken(cancellationToken));
.ToListAsync(GetCancellationToken(cancellationToken))
.ConfigureAwait(false);
}
public async Task<List<PersistedGrant>> GetListByExpirationAsync(
DateTime maxExpirationDate,
int maxResultCount,
CancellationToken cancellationToken = default)
{
return await DbSet
.Where(x => x.Expiration != null && x.Expiration < maxExpirationDate)
.OrderBy(x => x.ClientId)
.Take(maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken))
.ConfigureAwait(false);
}
public async Task DeleteAsync(

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using Volo.Abp.Domain.Repositories.MongoDB;
using Volo.Abp.IdentityServer.Devices;
@ -32,5 +34,18 @@ namespace Volo.Abp.IdentityServer.MongoDB
.FirstOrDefaultAsync(d => d.DeviceCode == deviceCode, GetCancellationToken(cancellationToken))
.ConfigureAwait(false);
}
public async Task<List<DeviceFlowCodes>> GetListByExpirationAsync(
DateTime maxExpirationDate,
int maxResultCount,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.Where(x => x.Expiration != null && x.Expiration < maxExpirationDate)
.OrderBy(x => x.ClientId)
.Take(maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken))
.ConfigureAwait(false);
}
}
}

@ -27,7 +27,19 @@ namespace Volo.Abp.IdentityServer.MongoDB
{
return await GetMongoQueryable()
.Where(x => x.SubjectId == subjectId)
.ToListAsync(GetCancellationToken(cancellationToken)).ConfigureAwait(false);
.ToListAsync(GetCancellationToken(cancellationToken))
.ConfigureAwait(false);
}
public async Task<List<PersistedGrant>> GetListByExpirationAsync(DateTime maxExpirationDate, int maxResultCount,
CancellationToken cancellationToken = default)
{
return await GetMongoQueryable()
.Where(x => x.Expiration != null && x.Expiration < maxExpirationDate)
.OrderBy(x => x.ClientId)
.Take(maxResultCount)
.ToListAsync(GetCancellationToken(cancellationToken))
.ConfigureAwait(false);
}
public async Task DeleteAsync(string subjectId, string clientId, CancellationToken cancellationToken = default)

Loading…
Cancel
Save