diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs index 66f9aea05a..5ce1ea9edc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemotePermissionChecker.cs @@ -1,4 +1,3 @@ -using System.Collections.Generic; using System.Security.Claims; using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AlwaysAllowPermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AlwaysAllowPermissionChecker.cs index 9efcfeb293..f3a90ec976 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AlwaysAllowPermissionChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/AlwaysAllowPermissionChecker.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.Linq; -using System.Security.Claims; +using System.Security.Claims; using System.Threading.Tasks; using Volo.Abp.Threading; @@ -31,12 +29,7 @@ namespace Volo.Abp.Authorization.Permissions public Task IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string[] names) { - var result = new MultiplePermissionGrantResult(); - foreach (var name in names) - { - result.Result.Add(name, PermissionGrantResult.Granted); - } - return Task.FromResult(result); + return Task.FromResult(new MultiplePermissionGrantResult(names, PermissionGrantResult.Granted)); } } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs index 5e9f34767b..7465acc087 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/ClientPermissionValueProvider.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Linq; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.Security.Claims; @@ -33,20 +32,15 @@ namespace Volo.Abp.Authorization.Permissions public async override Task CheckAsync(PermissionValuesCheckContext context) { - var result = new MultiplePermissionGrantResult(); - var permissionNames = context.Permissions.Select(x => x.Name).ToList(); - foreach (var name in permissionNames) - { - result.Result.Add(name, PermissionGrantResult.Undefined); - } + var permissionNames = context.Permissions.Select(x => x.Name).ToArray(); var clientId = context.Principal?.FindFirst(AbpClaimTypes.ClientId)?.Value; if (clientId == null) { - return result; + return new MultiplePermissionGrantResult(permissionNames);; } - return await PermissionStore.IsGrantedAsync(permissionNames.ToArray(), Name, clientId); + return await PermissionStore.IsGrantedAsync(permissionNames, Name, clientId); } } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/MultiplePermissionGrantResult.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/MultiplePermissionGrantResult.cs index dd0aff0633..5fc2293e76 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/MultiplePermissionGrantResult.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/MultiplePermissionGrantResult.cs @@ -27,5 +27,17 @@ namespace Volo.Abp.Authorization.Permissions { Result = new Dictionary(); } + + public MultiplePermissionGrantResult(string[] names, PermissionGrantResult grantResult = PermissionGrantResult.Undefined) + { + Check.NotNull(names, nameof(names)); + + Result = new Dictionary(); + + foreach (var name in names) + { + Result.Add(name, grantResult); + } + } } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullPermissionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullPermissionStore.cs index df2311d6b6..21b10b29b6 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullPermissionStore.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullPermissionStore.cs @@ -22,12 +22,7 @@ namespace Volo.Abp.Authorization.Permissions public Task IsGrantedAsync(string[] names, string providerName, string providerKey) { - var result = new MultiplePermissionGrantResult(); - foreach (var name in names) - { - result.Result.Add(name, PermissionGrantResult.Prohibited); - } - return Task.FromResult(result); + return Task.FromResult(new MultiplePermissionGrantResult(names, PermissionGrantResult.Prohibited)); } } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs index 49f5ba24e5..3f61df0b7e 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs @@ -88,12 +88,15 @@ namespace Volo.Abp.Authorization.Permissions { Check.NotNull(names, nameof(names)); - var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() - ?? CurrentTenant.GetMultiTenancySide(); + var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() ?? CurrentTenant.GetMultiTenancySide(); var result = new MultiplePermissionGrantResult(); + if (!names.Any()) + { + return result; + } - var definitions = new List(); + var permissionDefinitions = new List(); foreach (var name in names) { var permission = PermissionDefinitionManager.Get(name); @@ -104,22 +107,23 @@ namespace Volo.Abp.Authorization.Permissions } result.Result.Add(name, PermissionGrantResult.Undefined); - definitions.Add(permission); + permissionDefinitions.Add(permission); } foreach (var provider in PermissionValueProviderManager.ValueProviders) { - var context = new PermissionValuesCheckContext(definitions.Where(x => !x.Providers.Any() || x.Providers.Contains(provider.Name)).ToList(), + var context = new PermissionValuesCheckContext(permissionDefinitions.Where(x => !x.Providers.Any() || x.Providers.Contains(provider.Name)).ToList(), claimsPrincipal); - foreach (var grantResult in (await provider.CheckAsync(context)).Result) + var multipleResult = await provider.CheckAsync(context); + foreach (var grantResult in multipleResult.Result) { if (result.Result.ContainsKey(grantResult.Key) && result.Result[grantResult.Key] == PermissionGrantResult.Undefined && grantResult.Value != PermissionGrantResult.Undefined) { result.Result[grantResult.Key] = grantResult.Value; - definitions.Remove(definitions.First(x => x.Name == grantResult.Key)); + permissionDefinitions.RemoveAll(x => x.Name == grantResult.Key); } if (result.AllGranted || result.AllProhibited) diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs index 5ae21a3ecc..e8187f762a 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/RolePermissionValueProvider.cs @@ -39,12 +39,8 @@ namespace Volo.Abp.Authorization.Permissions public async override Task CheckAsync(PermissionValuesCheckContext context) { - var result = new MultiplePermissionGrantResult(); var permissionNames = context.Permissions.Select(x => x.Name).ToList(); - foreach (var name in permissionNames) - { - result.Result.Add(name, PermissionGrantResult.Undefined); - } + var result = new MultiplePermissionGrantResult(permissionNames.ToArray()); var roles = context.Principal?.FindAll(AbpClaimTypes.Role).Select(c => c.Value).ToArray(); if (roles == null || !roles.Any()) @@ -54,18 +50,19 @@ namespace Volo.Abp.Authorization.Permissions foreach (var role in roles) { - foreach (var grantResult in (await PermissionStore.IsGrantedAsync(permissionNames.ToArray(), Name, role)).Result) + var multipleResult = await PermissionStore.IsGrantedAsync(permissionNames.ToArray(), Name, role); + foreach (var grantResult in multipleResult.Result) { if (result.Result.ContainsKey(grantResult.Key) && result.Result[grantResult.Key] == PermissionGrantResult.Undefined && grantResult.Value != PermissionGrantResult.Undefined) { result.Result[grantResult.Key] = grantResult.Value; - permissionNames.Remove(grantResult.Key); + permissionNames.RemoveAll(x => x == grantResult.Key); } } - if (result.AllGranted) + if (result.AllGranted || result.AllProhibited) { break; } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs index ae40285cee..fcdc25d1e1 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/UserPermissionValueProvider.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.Linq; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.Security.Claims; @@ -33,20 +32,15 @@ namespace Volo.Abp.Authorization.Permissions public async override Task CheckAsync(PermissionValuesCheckContext context) { - var result = new MultiplePermissionGrantResult(); - var permissionNames = context.Permissions.Select(x => x.Name).ToList(); - foreach (var name in permissionNames) - { - result.Result.Add(name, PermissionGrantResult.Undefined); - } + var permissionNames = context.Permissions.Select(x => x.Name).ToArray(); var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value; if (userId == null) { - return result; + return new MultiplePermissionGrantResult(permissionNames); } - return await PermissionStore.IsGrantedAsync(permissionNames.ToArray(), Name, userId); + return await PermissionStore.IsGrantedAsync(permissionNames, Name, userId); } } } diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakePermissionStore.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakePermissionStore.cs index 6509d6dce2..fb4718e1c8 100644 --- a/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakePermissionStore.cs +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/Authorization/FakePermissionStore.cs @@ -24,7 +24,7 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization providerName == UserPermissionValueProvider.ProviderName && providerKey == AuthTestController.FakeUserId.ToString() ? PermissionGrantResult.Granted - : PermissionGrantResult.Undefined); + : PermissionGrantResult.Prohibited); } return Task.FromResult(result); diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItem.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItem.cs index 47a7e1530c..c3d9aacecd 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItem.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionGrantCacheItem.cs @@ -7,6 +7,8 @@ namespace Volo.Abp.PermissionManagement [Serializable] public class PermissionGrantCacheItem { + private const string CacheKeyFormat = "pn:{0},pk:{1},n:{2}"; + public bool IsGranted { get; set; } public PermissionGrantCacheItem() @@ -21,13 +23,12 @@ namespace Volo.Abp.PermissionManagement public static string CalculateCacheKey(string name, string providerName, string providerKey) { - return "pn:" + providerName + ",pk:" + providerKey + ",n:" + name; + return string.Format(CacheKeyFormat, providerName, providerKey, name); } - public static string ParseCacheKeyOrNull(string key) + public static string GetPermissionNameFormCacheKeyOrNull(string cacheKey) { - var format = "pn:{0},pk:{1},n:{2}"; - var result = FormattedStringValueExtracter.Extract(key, format, true); + var result = FormattedStringValueExtracter.Extract(cacheKey, CacheKeyFormat, true); return result.IsMatch ? result.Matches.Last().Value : null; } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs index b80c0b3fa1..9add7eb85b 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionStore.cs @@ -35,21 +35,6 @@ namespace Volo.Abp.PermissionManagement return (await GetCacheItemAsync(name, providerName, providerKey)).IsGranted; } - public virtual async Task IsGrantedAsync(string[] names, string providerName, string providerKey) - { - var result = new MultiplePermissionGrantResult(); - - var cacheItems = await GetCacheItemsAsync(names, providerName, providerKey); - foreach (var item in cacheItems) - { - result.Result.Add(PermissionGrantCacheItem.ParseCacheKeyOrNull(item.Key), item.Value.IsGranted - ? PermissionGrantResult.Granted : - PermissionGrantResult.Undefined); - } - - return result; - } - protected virtual async Task GetCacheItemAsync( string name, string providerName, @@ -114,27 +99,75 @@ namespace Volo.Abp.PermissionManagement Logger.LogDebug($"Finished setting the cache items. Count: {permissions.Count}"); } + public virtual async Task IsGrantedAsync(string[] names, string providerName, string providerKey) + { + Check.NotNullOrEmpty(names, nameof(names)); + + var result = new MultiplePermissionGrantResult(); + + if (names.Length == 1) + { + var name = names.First(); + result.Result.Add(name, + await IsGrantedAsync(names.First(), providerName, providerKey) + ? PermissionGrantResult.Granted + : PermissionGrantResult.Undefined); + return result; + } + + var cacheItems = await GetCacheItemsAsync(names, providerName, providerKey); + foreach (var item in cacheItems) + { + result.Result.Add(PermissionGrantCacheItem.GetPermissionNameFormCacheKeyOrNull(item.Key), + item.Value.IsGranted + ? PermissionGrantResult.Granted + : PermissionGrantResult.Undefined); + } + + return result; + } + protected virtual async Task>> GetCacheItemsAsync( string[] names, string providerName, string providerKey) { var cacheKeys = names.Select(x => CalculateCacheKey(x, providerName, providerKey)).ToList(); + + Logger.LogDebug($"PermissionStore.GetCacheItemAsync: {string.Join(",", cacheKeys)}"); + var cacheItems = (await Cache.GetManyAsync(cacheKeys)).ToList(); if (cacheItems.All(x => x.Value != null)) { + Logger.LogDebug($"Found in the cache: {string.Join(",", cacheKeys)}"); return cacheItems; } - return cacheItems.Where(x => x.Value != null) - .Union(await SetCacheItemsAsync(providerName, providerKey, cacheItems.Where(x => x.Value == null))) - .ToList(); + var notCacheKeys = cacheItems.Where(x => x.Value == null).Select(x => x.Key).ToList(); + + Logger.LogDebug($"Not found in the cache: {string.Join(",", notCacheKeys)}"); + + var newCacheItems = await SetCacheItemsAsync(providerName, providerKey, notCacheKeys); + + var result = new List>(); + foreach (var key in cacheKeys) + { + var item = newCacheItems.FirstOrDefault(x => x.Key == key); + if (item.Value == null) + { + item = cacheItems.FirstOrDefault(x => x.Key == key); + } + + result.Add(new KeyValuePair(key, item.Value)); + } + + return result; } protected virtual async Task>> SetCacheItemsAsync( string providerName, string providerKey, - IEnumerable> notCacheItems) + IEnumerable cacheKeys) { var permissions = PermissionDefinitionManager.GetPermissions(); @@ -162,7 +195,7 @@ namespace Volo.Abp.PermissionManagement Logger.LogDebug($"Finished setting the cache items. Count: {permissions.Count}"); - return cacheItems.Where(x => notCacheItems.Any(y => x.Key == y.Key)).ToList(); + return cacheItems.Where(x => cacheKeys.Contains(x.Key)).ToList(); } protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)