diff --git a/Volo.Abp.sln b/Volo.Abp.sln
index fc12143408..ff5187c3df 100644
--- a/Volo.Abp.sln
+++ b/Volo.Abp.sln
@@ -274,6 +274,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Permissions.Applic
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Permissions.Application", "src\Volo.Abp.Permissions.Application\Volo.Abp.Permissions.Application.csproj", "{90197499-CBB6-4C8C-90E6-8718CD755C04}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Caching", "src\Volo.Abp.Caching\Volo.Abp.Caching.csproj", "{A5B650AB-A67F-4A4C-9F81-7B5471CA1331}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -716,6 +718,10 @@ Global
{90197499-CBB6-4C8C-90E6-8718CD755C04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{90197499-CBB6-4C8C-90E6-8718CD755C04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{90197499-CBB6-4C8C-90E6-8718CD755C04}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A5B650AB-A67F-4A4C-9F81-7B5471CA1331}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A5B650AB-A67F-4A4C-9F81-7B5471CA1331}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A5B650AB-A67F-4A4C-9F81-7B5471CA1331}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A5B650AB-A67F-4A4C-9F81-7B5471CA1331}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -849,6 +855,7 @@ Global
{8859CFE4-BC7F-4F29-B6B5-A9457435CC32} = {055F4AC0-46C4-4E99-89CD-0F30D4A97382}
{837ABFF5-66EE-486A-8023-8DD3EE7D7D96} = {055F4AC0-46C4-4E99-89CD-0F30D4A97382}
{90197499-CBB6-4C8C-90E6-8718CD755C04} = {055F4AC0-46C4-4E99-89CD-0F30D4A97382}
+ {A5B650AB-A67F-4A4C-9F81-7B5471CA1331} = {4C753F64-0C93-4D65-96C2-A40893AFC1E8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5}
diff --git a/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj b/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj
new file mode 100644
index 0000000000..f588132fd6
--- /dev/null
+++ b/src/Volo.Abp.Caching/Volo.Abp.Caching.csproj
@@ -0,0 +1,24 @@
+
+
+
+
+
+ netstandard2.0
+ Volo.Abp.Caching
+ Volo.Abp.Caching
+ $(AssetTargetFallback);portable-net45+win8+wp8+wpa81;
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs b/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs
new file mode 100644
index 0000000000..114f093812
--- /dev/null
+++ b/src/Volo.Abp.Caching/Volo/Abp/Caching/AbpCachingModule.cs
@@ -0,0 +1,16 @@
+using Microsoft.Extensions.DependencyInjection;
+using Volo.Abp.Modularity;
+
+namespace Volo.Abp.Caching
+{
+ public class AbpCachingModule : AbpModule
+ {
+ public override void ConfigureServices(IServiceCollection services)
+ {
+ services.AddMemoryCache();
+ services.AddDistributedMemoryCache();
+
+ services.AddAssemblyOf();
+ }
+ }
+}
diff --git a/src/Volo.Abp.Permissions.Domain/Volo.Abp.Permissions.Domain.csproj b/src/Volo.Abp.Permissions.Domain/Volo.Abp.Permissions.Domain.csproj
index 6d5e9b7811..efd91d47a7 100644
--- a/src/Volo.Abp.Permissions.Domain/Volo.Abp.Permissions.Domain.csproj
+++ b/src/Volo.Abp.Permissions.Domain/Volo.Abp.Permissions.Domain.csproj
@@ -15,8 +15,16 @@
+
+
+
+
+ C:\Users\hikalkan\.nuget\packages\microsoft.extensions.caching.abstractions\2.0.0\lib\netstandard2.0\Microsoft.Extensions.Caching.Abstractions.dll
+
+
+
diff --git a/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/AbpPermissionsDomainModule.cs b/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/AbpPermissionsDomainModule.cs
index 4a3a9fd172..9d42682bbf 100644
--- a/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/AbpPermissionsDomainModule.cs
+++ b/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/AbpPermissionsDomainModule.cs
@@ -1,5 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization;
+using Volo.Abp.Caching;
+using Volo.Abp.Json;
using Volo.Abp.Modularity;
namespace Volo.Abp.Permissions
@@ -7,6 +9,8 @@ namespace Volo.Abp.Permissions
[DependsOn(typeof(AbpAuthorizationModule))]
[DependsOn(typeof(AbpDddModule))]
[DependsOn(typeof(AbpPermissionsDomainSharedModule))]
+ [DependsOn(typeof(AbpCachingModule))]
+ [DependsOn(typeof(AbpJsonModule))]
public class AbpPermissionsDomainModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
diff --git a/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionGrantCacheItem.cs b/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionGrantCacheItem.cs
new file mode 100644
index 0000000000..43e8db456f
--- /dev/null
+++ b/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionGrantCacheItem.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace Volo.Abp.Permissions
+{
+ [Serializable]
+ public class PermissionGrantCacheItem
+ {
+ public string Name { get; set; }
+
+ public bool IsGranted { get; set; }
+
+ public PermissionGrantCacheItem()
+ {
+
+ }
+
+ public PermissionGrantCacheItem(string name, bool isGranted)
+ {
+ Name = name;
+ IsGranted = isGranted;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionStore.cs b/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionStore.cs
index 79e5533725..ca67c9006c 100644
--- a/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionStore.cs
+++ b/src/Volo.Abp.Permissions.Domain/Volo/Abp/Permissions/PermissionStore.cs
@@ -1,21 +1,85 @@
-using System.Threading.Tasks;
+using System;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Caching.Distributed;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
+using Volo.Abp.Json;
+using Volo.Abp.MultiTenancy;
+using Volo.Abp.Threading;
namespace Volo.Abp.Permissions
{
+ /* TODOS:
+ * - Wrap distributed cache?
+ * - Add multi-tenancy
+ * - Add _cancellationTokenProvider support
+ * - Add object serialization support
+ * - Add cache invalidation support..? Maybe it's not cache's job!
+ */
+
public class PermissionStore : AbpServiceBase, IPermissionStore, ITransientDependency
{
private readonly IPermissionGrantRepository _permissionGrantRepository;
+ private readonly ICurrentTenant _currentTenant;
+ private readonly ICancellationTokenProvider _cancellationTokenProvider;
+ private readonly IDistributedCache _distributedCache;
+ private readonly IJsonSerializer _jsonSerializer;
- public PermissionStore(IPermissionGrantRepository permissionGrantRepository)
+ public PermissionStore(
+ IPermissionGrantRepository permissionGrantRepository,
+ IDistributedCache distributedCache,
+ ICancellationTokenProvider cancellationTokenProvider,
+ ICurrentTenant currentTenant,
+ IJsonSerializer jsonSerializer)
{
_permissionGrantRepository = permissionGrantRepository;
+ _distributedCache = distributedCache;
+ _cancellationTokenProvider = cancellationTokenProvider;
+ _currentTenant = currentTenant;
+ _jsonSerializer = jsonSerializer;
}
public async Task IsGrantedAsync(string name, string providerName, string providerKey)
{
return await _permissionGrantRepository.FindAsync(name, providerName, providerKey) != null;
+ //return (await GetCacheItemAsync(name, providerName, providerKey)).IsGranted; //TODO: Use cache when invalidation is possible!
+ }
+
+ private string CalculateCacheKey(string name, string providerName, string providerKey)
+ {
+ var key = "P:" + providerName + "_K:" + providerKey + "N:" + name;
+
+ if (_currentTenant.Id.HasValue)
+ {
+ key = "T:" + _currentTenant.Id + "_" + key;
+ }
+
+ return key;
+ }
+
+ private async Task GetCacheItemAsync(string name, string providerName, string providerKey)
+ {
+ var cacheKey = CalculateCacheKey(name, providerName, providerKey);
+ var cachedString = await _distributedCache.GetStringAsync(cacheKey, _cancellationTokenProvider.Token);
+
+ if (cachedString != null)
+ {
+ return _jsonSerializer.Deserialize(cachedString);
+ }
+
+ var cacheItem = new PermissionGrantCacheItem(
+ name,
+ await _permissionGrantRepository.FindAsync(name, providerName, providerKey) != null
+ );
+
+ await _distributedCache.SetStringAsync(
+ cacheKey,
+ _jsonSerializer.Serialize(cacheItem),
+ new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(20) },
+ _cancellationTokenProvider.Token
+ );
+
+ return cacheItem;
}
}
}
diff --git a/src/Volo.Abp.Permissions.EntityFrameworkCore/Volo/Abp/Permissions/EntityFrameworkCore/EfCorePermissionGrantRepository.cs b/src/Volo.Abp.Permissions.EntityFrameworkCore/Volo/Abp/Permissions/EntityFrameworkCore/EfCorePermissionGrantRepository.cs
index 261781b3b9..e907c82ed7 100644
--- a/src/Volo.Abp.Permissions.EntityFrameworkCore/Volo/Abp/Permissions/EntityFrameworkCore/EfCorePermissionGrantRepository.cs
+++ b/src/Volo.Abp.Permissions.EntityFrameworkCore/Volo/Abp/Permissions/EntityFrameworkCore/EfCorePermissionGrantRepository.cs
@@ -18,12 +18,19 @@ namespace Volo.Abp.Permissions.EntityFrameworkCore
public async Task FindAsync(string name, string providerName, string providerKey)
{
- return await DbSet.FirstOrDefaultAsync(s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey);
+ return await DbSet.FirstOrDefaultAsync(s =>
+ s.Name == name &&
+ s.ProviderName == providerName &&
+ s.ProviderKey == providerKey
+ );
}
public async Task> GetListAsync(string providerName, string providerKey)
{
- return await DbSet.Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync();
+ return await DbSet.Where(s =>
+ s.ProviderName == providerName &&
+ s.ProviderKey == providerKey
+ ).ToListAsync();
}
}
}
diff --git a/src/Volo.Abp/Volo.Abp.csproj b/src/Volo.Abp/Volo.Abp.csproj
index 168637c9e8..ced7db9c3c 100644
--- a/src/Volo.Abp/Volo.Abp.csproj
+++ b/src/Volo.Abp/Volo.Abp.csproj
@@ -16,6 +16,7 @@
+
diff --git a/src/Volo.Abp/Volo/Abp/AbpCommonModule.cs b/src/Volo.Abp/Volo/Abp/AbpCommonModule.cs
index 12ea477ed8..639e80fecc 100644
--- a/src/Volo.Abp/Volo/Abp/AbpCommonModule.cs
+++ b/src/Volo.Abp/Volo/Abp/AbpCommonModule.cs
@@ -1,6 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.ApiVersioning;
using Volo.Abp.Authorization;
+using Volo.Abp.Caching;
using Volo.Abp.Data;
using Volo.Abp.Json;
using Volo.Abp.Localization;
@@ -27,6 +28,7 @@ namespace Volo.Abp
[DependsOn(typeof(AbpVirtualFileSystemModule))]
[DependsOn(typeof(AbpApiVersioningAbstractionsModule))]
[DependsOn(typeof(AbpMultiTenancyAbstractionsModule))]
+ [DependsOn(typeof(AbpCachingModule))]
public class AbpCommonModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
diff --git a/test/Volo.Abp.Identity.Tests/Volo/Abp/Identity/PermissionManager_Tests.cs b/test/Volo.Abp.Identity.Tests/Volo/Abp/Identity/PermissionManager_Tests.cs
index fb782aea56..8deb512cad 100644
--- a/test/Volo.Abp.Identity.Tests/Volo/Abp/Identity/PermissionManager_Tests.cs
+++ b/test/Volo.Abp.Identity.Tests/Volo/Abp/Identity/PermissionManager_Tests.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
+using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Permissions;
using Volo.Abp.Session;
using Xunit;
@@ -12,10 +13,12 @@ namespace Volo.Abp.Identity
public class PermissionManager_Tests : AbpIdentityDomainTestBase
{
private readonly IPermissionManager _permissionManager;
+ private readonly IPermissionStore _permissionStore;
public PermissionManager_Tests()
{
_permissionManager = GetRequiredService();
+ _permissionStore = GetRequiredService();
}
[Fact]
@@ -44,8 +47,12 @@ namespace Volo.Abp.Identity
public async Task Should_Grant_Permission_To_Role()
{
(await _permissionManager.GetForRoleAsync("supporter", TestPermissionNames.MyPermission2)).IsGranted.ShouldBeFalse();
+ (await _permissionStore.IsGrantedAsync(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "supporter")).ShouldBeFalse();
+
await _permissionManager.SetForRoleAsync("supporter", TestPermissionNames.MyPermission2, true);
+
(await _permissionManager.GetForRoleAsync("supporter", TestPermissionNames.MyPermission2)).IsGranted.ShouldBeTrue();
+ (await _permissionStore.IsGrantedAsync(TestPermissionNames.MyPermission2, RolePermissionValueProvider.ProviderName, "supporter")).ShouldBeTrue();
}
[Fact]