Browse Source

complete initial DynamicPermissionDefinitionStore

pull/13644/head
Halil İbrahim Kalkan 4 years ago
parent
commit
5db75833af
  1. 64
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs
  2. 67
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs
  3. 23
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs
  4. 23
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs

64
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStore.cs

@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Threading;
namespace Volo.Abp.PermissionManagement;
@ -12,35 +15,72 @@ public class DynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStor
protected IPermissionGroupDefinitionRecordRepository PermissionGroupRepository { get; }
protected IPermissionDefinitionRecordRepository PermissionRepository { get; }
protected IPermissionDefinitionSerializer PermissionDefinitionSerializer { get; }
protected IDynamicPermissionDefinitionStoreInMemoryCache StoreCache { get; }
protected IDistributedCache DistributedCache { get; }
protected AbpDistributedCacheOptions CacheOptions { get; }
public DynamicPermissionDefinitionStore(
IPermissionGroupDefinitionRecordRepository permissionGroupRepository,
IPermissionDefinitionRecordRepository permissionRepository,
IPermissionDefinitionSerializer permissionDefinitionSerializer)
IPermissionDefinitionSerializer permissionDefinitionSerializer,
IDynamicPermissionDefinitionStoreInMemoryCache storeCache,
IDistributedCache distributedCache,
IOptions<AbpDistributedCacheOptions> cacheOptions)
{
PermissionGroupRepository = permissionGroupRepository;
PermissionRepository = permissionRepository;
PermissionDefinitionSerializer = permissionDefinitionSerializer;
StoreCache = storeCache;
DistributedCache = distributedCache;
CacheOptions = cacheOptions.Value;
}
public virtual async Task<PermissionDefinition> GetOrNullAsync(string name)
{
var permissionRecord = await PermissionRepository.FindByNameAsync(name);
if (permissionRecord == null)
{
return null;
}
throw new NotImplementedException();
await EnsureCacheIsUptoDateAsync();
return StoreCache.GetPermissionOrNull(name);
}
public virtual async Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync()
{
throw new NotImplementedException();
await EnsureCacheIsUptoDateAsync();
return StoreCache.GetPermissions();
}
public virtual async Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
{
throw new NotImplementedException();
await EnsureCacheIsUptoDateAsync();
return StoreCache.GetGroups();
}
private async Task EnsureCacheIsUptoDateAsync()
{
/* TODO: Optimization note: May not check for a few seconds
* It is acceptable to get changes a few seconds after the last time the cache was updated.
*/
using (await StoreCache.SyncSemaphore.LockAsync())
{
var cacheKey = GetCacheKey();
var stampInDistributedCache = await DistributedCache.GetStringAsync(cacheKey);
if (StoreCache.CacheStamp == stampInDistributedCache)
{
return;
}
var permissionGroupRecords = await PermissionGroupRepository.GetListAsync();
var permissionRecords = await PermissionRepository.GetListAsync();
await StoreCache.FillAsync(permissionGroupRecords, permissionRecords);
StoreCache.CacheStamp = stampInDistributedCache;
}
}
private string GetCacheKey()
{
return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp";
}
}

67
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreCache.cs → modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/DynamicPermissionDefinitionStoreInMemoryCache.cs

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
@ -9,27 +10,32 @@ using Volo.Abp.SimpleStateChecking;
namespace Volo.Abp.PermissionManagement;
//TODO: Extract interface
public class DynamicPermissionDefinitionStoreCache : ISingletonDependency
public class DynamicPermissionDefinitionStoreInMemoryCache :
IDynamicPermissionDefinitionStoreInMemoryCache,
ISingletonDependency
{
public string CacheStamp { get; set; }
protected IDictionary<string, PermissionGroupDefinition> PermissionGroupDefinitions { get; }
protected IDictionary<string, PermissionDefinition> PermissionDefinitions { get; }
protected ISimpleStateCheckerSerializer StateCheckerSerializer { get; }
public DynamicPermissionDefinitionStoreCache(ISimpleStateCheckerSerializer stateCheckerSerializer)
public DynamicPermissionDefinitionStoreInMemoryCache(ISimpleStateCheckerSerializer stateCheckerSerializer)
{
StateCheckerSerializer = stateCheckerSerializer;
PermissionGroupDefinitions = new Dictionary<string, PermissionGroupDefinition>();
PermissionDefinitions = new Dictionary<string, PermissionDefinition>();
}
public SemaphoreSlim SyncSemaphore { get; } = new(1, 1);
public Task FillAsync(
List<PermissionGroupDefinitionRecord> permissionGroupRecords,
List<PermissionDefinitionRecord> permissionRecords)
{
PermissionGroupDefinitions.Clear();
PermissionDefinitions.Clear();
var context = new PermissionDefinitionContext(null);
foreach (var permissionGroupRecord in permissionGroupRecords)
@ -38,6 +44,8 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency
permissionGroupRecord.Name,
new FixedLocalizableString(permissionGroupRecord.DisplayName) //TODO: Consider localization
);
PermissionGroupDefinitions[permissionGroup.Name] = permissionGroup;
foreach (var property in permissionGroupRecord.ExtraProperties)
{
@ -52,10 +60,25 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency
AddPermissionRecursively(permissionGroup, permissionRecord, permissionRecords);
}
}
return Task.CompletedTask;
}
public PermissionDefinition GetPermissionOrNull(string name)
{
return PermissionDefinitions.GetOrDefault(name);
}
public IReadOnlyList<PermissionDefinition> GetPermissions()
{
return PermissionDefinitions.Values.ToList();
}
public IReadOnlyList<PermissionGroupDefinition> GetGroups()
{
return PermissionGroupDefinitions.Values.ToList();
}
private void AddPermissionRecursively(ICanAddChildPermission permissionContainer,
PermissionDefinitionRecord permissionRecord,
List<PermissionDefinitionRecord> allPermissionRecords)
@ -66,6 +89,8 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency
permissionRecord.MultiTenancySide,
permissionRecord.IsEnabled
);
PermissionDefinitions[permission.Name] = permission;
if (!permissionRecord.Providers.IsNullOrWhiteSpace())
{
@ -91,36 +116,4 @@ public class DynamicPermissionDefinitionStoreCache : ISingletonDependency
AddPermissionRecursively(permission, subPermission, allPermissionRecords);
}
}
protected virtual Dictionary<string, PermissionDefinition> CreatePermissionDefinitions()
{
var permissions = new Dictionary<string, PermissionDefinition>();
foreach (var groupDefinition in PermissionGroupDefinitions.Values)
{
foreach (var permission in groupDefinition.Permissions)
{
AddPermissionToDictionaryRecursively(permissions, permission);
}
}
return permissions;
}
protected virtual void AddPermissionToDictionaryRecursively(
Dictionary<string, PermissionDefinition> permissions,
PermissionDefinition permission)
{
if (permissions.ContainsKey(permission.Name))
{
throw new AbpException("Duplicate permission name: " + permission.Name);
}
permissions[permission.Name] = permission;
foreach (var child in permission.Children)
{
AddPermissionToDictionaryRecursively(permissions, child);
}
}
}

23
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IDynamicPermissionDefinitionStoreInMemoryCache.cs

@ -0,0 +1,23 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions;
namespace Volo.Abp.PermissionManagement;
public interface IDynamicPermissionDefinitionStoreInMemoryCache
{
string CacheStamp { get; set; }
SemaphoreSlim SyncSemaphore { get; }
Task FillAsync(
List<PermissionGroupDefinitionRecord> permissionGroupRecords,
List<PermissionDefinitionRecord> permissionRecords);
PermissionDefinition GetPermissionOrNull(string name);
IReadOnlyList<PermissionDefinition> GetPermissions();
IReadOnlyList<PermissionGroupDefinition> GetGroups();
}

23
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/StaticPermissionSaver.cs

@ -22,8 +22,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc
protected IPermissionDefinitionSerializer PermissionSerializer { get; }
protected IDistributedCache Cache { get; }
protected IApplicationNameAccessor ApplicationNameAccessor { get; }
public IAbpDistributedLock DistributedLock { get; }
public PermissionManagementOptions PermissionManagementOptions { get; }
protected IAbpDistributedLock DistributedLock { get; }
protected PermissionManagementOptions PermissionManagementOptions { get; }
protected AbpDistributedCacheOptions CacheOptions { get; }
public StaticPermissionSaver(
@ -51,6 +51,8 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc
[UnitOfWork]
public virtual async Task SaveAsync()
{
/* TODO: We may double check and lock for optimization
*/
await using var handle = await DistributedLock.TryAcquireAsync(GetDistributedLockKey());
if (handle == null)
@ -64,7 +66,7 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc
* But the code would be more complex.
*/
var cacheKey = GetCacheKey();
var cacheKey = GetApplicationHashCacheKey();
var cachedHash = await Cache.GetStringAsync(cacheKey);
var (permissionGroupRecords, permissionRecords) = await PermissionSerializer.SerializeAsync(
@ -93,6 +95,14 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc
SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable?
}
);
await Cache.SetStringAsync(
GetCommonStampCacheKey(),
Guid.NewGuid().ToString(),
new DistributedCacheEntryOptions {
SlidingExpiration = TimeSpan.FromDays(30) //TODO: Make it configurable?
}
);
}
private async Task UpdateChangedPermissionGroupsAsync(IEnumerable<PermissionGroupDefinitionRecord> permissionGroupRecords)
@ -204,10 +214,15 @@ public class StaticPermissionSaver : IStaticPermissionSaver, ITransientDependenc
return $"{ApplicationNameAccessor.ApplicationName}_AbpPermissionUpdateLock";
}
private string GetCacheKey()
private string GetApplicationHashCacheKey()
{
return $"{CacheOptions.KeyPrefix}_{ApplicationNameAccessor.ApplicationName}_AbpPermissionsHash";
}
private string GetCommonStampCacheKey()
{
return $"{CacheOptions.KeyPrefix}_AbpInMemoryPermissionCacheStamp";
}
private static string CalculateHash(
PermissionGroupDefinitionRecord[] permissionGroupRecords,

Loading…
Cancel
Save