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 18f5272e7b..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,4 @@ -using System.Security.Claims; +using System.Security.Claims; using System.Threading.Tasks; using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; @@ -26,5 +26,25 @@ namespace Volo.Abp.AspNetCore.Mvc.Client /* This provider always works for the current principal. */ return await IsGrantedAsync(name); } + + public async Task IsGrantedAsync(string[] names) + { + var result = new MultiplePermissionGrantResult(); + var configuration = await ConfigurationClient.GetAsync(); + foreach (var name in names) + { + result.Result.Add(name, configuration.Auth.GrantedPolicies.ContainsKey(name) ? + PermissionGrantResult.Granted : + PermissionGrantResult.Undefined); + } + + return result; + } + + public async Task IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string[] names) + { + /* This provider always works for the current principal. */ + return await IsGrantedAsync(names); + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs index db3ea6e9a6..89db44b43d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Client.Common/Volo/Abp/AspNetCore/Mvc/Client/RemoteSettingProvider.cs @@ -14,13 +14,19 @@ namespace Volo.Abp.AspNetCore.Mvc.Client { ConfigurationClient = configurationClient; } - + public async Task GetOrNullAsync(string name) { var configuration = await ConfigurationClient.GetAsync(); return configuration.Setting.Values.GetOrDefault(name); } + public async Task> GetAllAsync(string[] names) + { + var configuration = await ConfigurationClient.GetAsync(); + return names.Select(x => new SettingValue(x, configuration.Setting.Values.GetOrDefault(x))).ToList(); + } + public async Task> GetAllAsync() { var configuration = await ConfigurationClient.GetAsync(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs index 89bf3e7cfc..eab7d968a9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/AbpApplicationConfigurationAppService.cs @@ -5,12 +5,14 @@ using Microsoft.Extensions.Options; using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Volo.Abp.Application.Services; using Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending; using Volo.Abp.AspNetCore.Mvc.MultiTenancy; using Volo.Abp.Authorization; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.Features; using Volo.Abp.Localization; using Volo.Abp.MultiTenancy; @@ -26,6 +28,9 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations private readonly AbpMultiTenancyOptions _multiTenancyOptions; private readonly IServiceProvider _serviceProvider; private readonly IAbpAuthorizationPolicyProvider _abpAuthorizationPolicyProvider; + private readonly IPermissionDefinitionManager _permissionDefinitionManager; + private readonly DefaultAuthorizationPolicyProvider _defaultAuthorizationPolicyProvider; + private readonly IPermissionChecker _permissionChecker; private readonly IAuthorizationService _authorizationService; private readonly ICurrentUser _currentUser; private readonly ISettingProvider _settingProvider; @@ -41,6 +46,9 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations IOptions multiTenancyOptions, IServiceProvider serviceProvider, IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider, + IPermissionDefinitionManager permissionDefinitionManager, + DefaultAuthorizationPolicyProvider defaultAuthorizationPolicyProvider, + IPermissionChecker permissionChecker, IAuthorizationService authorizationService, ICurrentUser currentUser, ISettingProvider settingProvider, @@ -53,6 +61,9 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations { _serviceProvider = serviceProvider; _abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider; + _permissionDefinitionManager = permissionDefinitionManager; + _defaultAuthorizationPolicyProvider = defaultAuthorizationPolicyProvider; + _permissionChecker = permissionChecker; _authorizationService = authorizationService; _currentUser = currentUser; _settingProvider = settingProvider; @@ -132,8 +143,22 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations var authConfig = new ApplicationAuthConfigurationDto(); var policyNames = await _abpAuthorizationPolicyProvider.GetPoliciesNamesAsync(); + var abpPolicyNames = new List(); + var otherPolicyNames = new List(); foreach (var policyName in policyNames) + { + if(await _defaultAuthorizationPolicyProvider.GetPolicyAsync(policyName) == null && _permissionDefinitionManager.GetOrNull(policyName) != null) + { + abpPolicyNames.Add(policyName); + } + else + { + otherPolicyNames.Add(policyName); + } + } + + foreach (var policyName in otherPolicyNames) { authConfig.Policies[policyName] = true; @@ -143,6 +168,16 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations } } + var result = await _permissionChecker.IsGrantedAsync(abpPolicyNames.ToArray()); + foreach (var (key, value) in result.Result) + { + authConfig.Policies[key] = true; + if (value == PermissionGrantResult.Granted) + { + authConfig.GrantedPolicies[key] = true; + } + } + return authConfig; } @@ -216,14 +251,13 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations Values = new Dictionary() }; - foreach (var settingDefinition in _settingDefinitionManager.GetAll()) - { - if (!settingDefinition.IsVisibleToClients) - { - continue; - } + var settingDefinitions = _settingDefinitionManager.GetAll().Where(x => x.IsVisibleToClients); - result.Values[settingDefinition.Name] = await _settingProvider.GetOrNullAsync(settingDefinition.Name); + var settingValues = await _settingProvider.GetAllAsync(settingDefinitions.Select(x => x.Name).ToArray()); + + foreach (var settingValue in settingValues) + { + result.Values[settingValue.Name] = settingValue.Value; } return result; diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs index 86b2b18d04..b16e08a214 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Authorization.Permissions; using Volo.Abp.Localization; using Volo.Abp.Modularity; @@ -29,6 +30,8 @@ namespace Volo.Abp.Authorization context.Services.AddSingleton(); + context.Services.TryAddTransient(); + Configure(options => { options.ValueProviders.Add(); 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 e3f4425289..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 @@ -6,7 +6,7 @@ namespace Volo.Abp.Authorization.Permissions { /// /// Always allows for any permission. - /// + /// /// Use IServiceCollection.AddAlwaysAllowAuthorization() to replace /// IPermissionChecker with this class. This is useful for tests. /// @@ -21,5 +21,15 @@ namespace Volo.Abp.Authorization.Permissions { return TaskCache.TrueResult; } + + public Task IsGrantedAsync(string[] names) + { + return IsGrantedAsync(null, names); + } + + public Task IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string[] names) + { + 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 b3b68b109c..ac76733524 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,6 @@ using System.Threading.Tasks; using Volo.Abp.MultiTenancy; +using System.Linq; using Volo.Abp.Security.Claims; namespace Volo.Abp.Authorization.Permissions @@ -34,5 +35,21 @@ namespace Volo.Abp.Authorization.Permissions : PermissionGrantResult.Undefined; } } + + public async override Task CheckAsync(PermissionValuesCheckContext context) + { + var permissionNames = context.Permissions.Select(x => x.Name).ToArray(); + + var clientId = context.Principal?.FindFirst(AbpClaimTypes.ClientId)?.Value; + if (clientId == null) + { + return new MultiplePermissionGrantResult(permissionNames);; + } + + using (CurrentTenant.Change(null)) + { + return await PermissionStore.IsGrantedAsync(permissionNames, Name, clientId); + } + } } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionChecker.cs index b394a29f52..a172e8da95 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionChecker.cs @@ -9,5 +9,9 @@ namespace Volo.Abp.Authorization.Permissions Task IsGrantedAsync([NotNull]string name); Task IsGrantedAsync([CanBeNull] ClaimsPrincipal claimsPrincipal, [NotNull]string name); + + Task IsGrantedAsync([NotNull]string[] names); + + Task IsGrantedAsync([CanBeNull] ClaimsPrincipal claimsPrincipal, [NotNull]string[] names); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionStore.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionStore.cs index b2d077d3c7..08ca09fc72 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionStore.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionStore.cs @@ -10,5 +10,11 @@ namespace Volo.Abp.Authorization.Permissions [CanBeNull] string providerName, [CanBeNull] string providerKey ); + + Task IsGrantedAsync( + [NotNull] string[] names, + [CanBeNull] string providerName, + [CanBeNull] string providerKey + ); } } diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionValueProvider.cs index a9b5e78337..9d69b6d55d 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IPermissionValueProvider.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; namespace Volo.Abp.Authorization.Permissions { @@ -8,5 +9,7 @@ namespace Volo.Abp.Authorization.Permissions //TODO: Rename to GetResult? (CheckAsync throws exception by naming convention) Task CheckAsync(PermissionValueCheckContext context); + + Task CheckAsync(PermissionValuesCheckContext context); } -} \ No newline at end of file +} 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 new file mode 100644 index 0000000000..5fc2293e76 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/MultiplePermissionGrantResult.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Volo.Abp.Authorization.Permissions +{ + public class MultiplePermissionGrantResult + { + public bool AllGranted + { + get + { + return Result.Values.All(x => x == PermissionGrantResult.Granted); + } + } + + public bool AllProhibited + { + get + { + return Result.Values.All(x => x == PermissionGrantResult.Prohibited); + } + } + + public Dictionary Result { get; } + + public MultiplePermissionGrantResult() + { + 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 57c76ac6c9..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 @@ -19,5 +19,10 @@ namespace Volo.Abp.Authorization.Permissions { return TaskCache.FalseResult; } + + public Task IsGrantedAsync(string[] names, string providerName, string providerKey) + { + return Task.FromResult(new MultiplePermissionGrantResult(names, PermissionGrantResult.Prohibited)); + } } -} \ No newline at end of file +} 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 931c9d1d23..bfdcf5fd66 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 @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Security.Claims; using System.Security.Principal; using System.Threading.Tasks; @@ -17,7 +18,7 @@ namespace Volo.Abp.Authorization.Permissions public PermissionChecker( ICurrentPrincipalAccessor principalAccessor, - IPermissionDefinitionManager permissionDefinitionManager, + IPermissionDefinitionManager permissionDefinitionManager, ICurrentTenant currentTenant, IPermissionValueProviderManager permissionValueProviderManager) { @@ -33,7 +34,7 @@ namespace Volo.Abp.Authorization.Permissions } public virtual async Task IsGrantedAsync( - ClaimsPrincipal claimsPrincipal, + ClaimsPrincipal claimsPrincipal, string name) { Check.NotNull(name, nameof(name)); @@ -77,5 +78,60 @@ namespace Volo.Abp.Authorization.Permissions return isGranted; } + + public async Task IsGrantedAsync(string[] names) + { + return await IsGrantedAsync(PrincipalAccessor.Principal, names); + } + + public async Task IsGrantedAsync(ClaimsPrincipal claimsPrincipal, string[] names) + { + Check.NotNull(names, nameof(names)); + + var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() ?? CurrentTenant.GetMultiTenancySide(); + + var result = new MultiplePermissionGrantResult(); + if (!names.Any()) + { + return result; + } + + var permissionDefinitions = new List(); + foreach (var name in names) + { + var permission = PermissionDefinitionManager.Get(name); + + result.Result.Add(name, PermissionGrantResult.Undefined); + + if (permission.IsEnabled && permission.MultiTenancySide.HasFlag(multiTenancySide)) + { + permissionDefinitions.Add(permission); + } + } + + foreach (var provider in PermissionValueProviderManager.ValueProviders) + { + var context = new PermissionValuesCheckContext( + permissionDefinitions.Where(x => !x.Providers.Any() || x.Providers.Contains(provider.Name)).ToList(), + claimsPrincipal); + + var multipleResult = await provider.CheckAsync(context); + foreach (var grantResult in multipleResult.Result.Where(grantResult => + result.Result.ContainsKey(grantResult.Key) && + result.Result[grantResult.Key] == PermissionGrantResult.Undefined && + grantResult.Value != PermissionGrantResult.Undefined)) + { + result.Result[grantResult.Key] = grantResult.Value; + permissionDefinitions.RemoveAll(x => x.Name == grantResult.Key); + } + + if (result.AllGranted || result.AllProhibited) + { + break; + } + } + + return result; + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProvider.cs index d15311b77c..47ed4e7722 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProvider.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Authorization.Permissions @@ -15,5 +16,7 @@ namespace Volo.Abp.Authorization.Permissions } public abstract Task CheckAsync(PermissionValueCheckContext context); + + public abstract Task CheckAsync(PermissionValuesCheckContext context); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValuesCheckContext.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValuesCheckContext.cs new file mode 100644 index 0000000000..e9014eff94 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValuesCheckContext.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using System.Security.Claims; +using JetBrains.Annotations; + +namespace Volo.Abp.Authorization.Permissions +{ + public class PermissionValuesCheckContext + { + [NotNull] + public List Permissions { get; } + + [CanBeNull] + public ClaimsPrincipal Principal { get; } + + public PermissionValuesCheckContext( + [NotNull] List permissions, + [CanBeNull] ClaimsPrincipal principal) + { + Check.NotNull(permissions, nameof(permissions)); + + Permissions = permissions; + Principal = principal; + } + } +} 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 a458cd8fdb..e3ab7629a2 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 @@ -1,4 +1,5 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.Security.Claims; @@ -35,5 +36,37 @@ namespace Volo.Abp.Authorization.Permissions return PermissionGrantResult.Undefined; } + + public async override Task CheckAsync(PermissionValuesCheckContext context) + { + var permissionNames = context.Permissions.Select(x => x.Name).ToList(); + var result = new MultiplePermissionGrantResult(permissionNames.ToArray()); + + var roles = context.Principal?.FindAll(AbpClaimTypes.Role).Select(c => c.Value).ToArray(); + if (roles == null || !roles.Any()) + { + return result; + } + + foreach (var role in roles) + { + var multipleResult = await PermissionStore.IsGrantedAsync(permissionNames.ToArray(), Name, role); + foreach (var grantResult in multipleResult.Result.Where(grantResult => + result.Result.ContainsKey(grantResult.Key) && + result.Result[grantResult.Key] == PermissionGrantResult.Undefined && + grantResult.Value != PermissionGrantResult.Undefined)) + { + result.Result[grantResult.Key] = grantResult.Value; + permissionNames.RemoveAll(x => x == grantResult.Key); + } + + if (result.AllGranted || result.AllProhibited) + { + break; + } + } + + return result; + } } } 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 204b928e61..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,4 +1,5 @@ -using System.Threading.Tasks; +using System.Linq; +using System.Threading.Tasks; using Volo.Abp.Security.Claims; namespace Volo.Abp.Authorization.Permissions @@ -28,5 +29,18 @@ namespace Volo.Abp.Authorization.Permissions ? PermissionGrantResult.Granted : PermissionGrantResult.Undefined; } + + public async override Task CheckAsync(PermissionValuesCheckContext context) + { + var permissionNames = context.Permissions.Select(x => x.Name).ToArray(); + + var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value; + if (userId == null) + { + return new MultiplePermissionGrantResult(permissionNames); + } + + return await PermissionStore.IsGrantedAsync(permissionNames, Name, userId); + } } } diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ConfigurationSettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ConfigurationSettingValueProvider.cs index 70f2a6c346..ec5fa91eac 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ConfigurationSettingValueProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ConfigurationSettingValueProvider.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.Configuration; using Volo.Abp.DependencyInjection; @@ -23,5 +25,10 @@ namespace Volo.Abp.Settings { return Task.FromResult(Configuration[ConfigurationNamePrefix + setting.Name]); } + + public Task> GetAllAsync(SettingDefinition[] settings) + { + return Task.FromResult(settings.Select(x => new SettingValue(x.Name, Configuration[ConfigurationNamePrefix + x.Name])).ToList()); + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/DefaultValueSettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/DefaultValueSettingValueProvider.cs index 201e4f26c4..5575ed3f23 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/DefaultValueSettingValueProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/DefaultValueSettingValueProvider.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; namespace Volo.Abp.Settings { @@ -8,7 +10,7 @@ namespace Volo.Abp.Settings public override string Name => ProviderName; - public DefaultValueSettingValueProvider(ISettingStore settingStore) + public DefaultValueSettingValueProvider(ISettingStore settingStore) : base(settingStore) { @@ -18,5 +20,10 @@ namespace Volo.Abp.Settings { return Task.FromResult(setting.DefaultValue); } + + public override Task> GetAllAsync(SettingDefinition[] settings) + { + return Task.FromResult(settings.Select(x => new SettingValue(x.Name, x.DefaultValue)).ToList()); + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/GlobalSettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/GlobalSettingValueProvider.cs index 1a69a4ba90..48ad3492ef 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/GlobalSettingValueProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/GlobalSettingValueProvider.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; namespace Volo.Abp.Settings { @@ -8,7 +10,7 @@ namespace Volo.Abp.Settings public override string Name => ProviderName; - public GlobalSettingValueProvider(ISettingStore settingStore) + public GlobalSettingValueProvider(ISettingStore settingStore) : base(settingStore) { } @@ -17,5 +19,10 @@ namespace Volo.Abp.Settings { return SettingStore.GetOrNullAsync(setting.Name, Name, null); } + + public override Task> GetAllAsync(SettingDefinition[] settings) + { + return SettingStore.GetAllAsync(settings.Select(x => x.Name).ToArray(), Name, null); + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingProvider.cs index 608cf49105..3979c6be6b 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingProvider.cs @@ -8,6 +8,8 @@ namespace Volo.Abp.Settings { Task GetOrNullAsync([NotNull]string name); + Task> GetAllAsync([NotNull]string[] names); + Task> GetAllAsync(); } } diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingStore.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingStore.cs index 69e6319a2f..2ad7055e96 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingStore.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingStore.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using JetBrains.Annotations; namespace Volo.Abp.Settings @@ -10,5 +11,11 @@ namespace Volo.Abp.Settings [CanBeNull] string providerName, [CanBeNull] string providerKey ); + + Task> GetAllAsync( + [NotNull] string[] names, + [CanBeNull] string providerName, + [CanBeNull] string providerKey + ); } } diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingValueProvider.cs index ab63f47d17..1f64197373 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingValueProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/ISettingValueProvider.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using JetBrains.Annotations; namespace Volo.Abp.Settings @@ -8,5 +9,7 @@ namespace Volo.Abp.Settings string Name { get; } Task GetOrNullAsync([NotNull] SettingDefinition setting); + + Task> GetAllAsync([NotNull] SettingDefinition[] settings); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/NullSettingStore.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/NullSettingStore.cs index 8699fae972..58fbf5627f 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/NullSettingStore.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/NullSettingStore.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; using Volo.Abp.DependencyInjection; @@ -19,5 +21,10 @@ namespace Volo.Abp.Settings { return Task.FromResult((string) null); } + + public Task> GetAllAsync(string[] names, string providerName, string providerKey) + { + return Task.FromResult(names.Select(x => new SettingValue(x, null)).ToList()); + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs index 5ef67cbc21..52ef5c50de 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingProvider.cs @@ -43,29 +43,52 @@ namespace Volo.Abp.Settings return value; } - public virtual async Task> GetAllAsync() + public async Task> GetAllAsync(string[] names) { - var settingValues = new Dictionary(); - var settingDefinitions = SettingDefinitionManager.GetAll(); + var result = new Dictionary(); + var settingDefinitions = SettingDefinitionManager.GetAll().Where(x => names.Contains(x.Name)).ToList(); + + foreach (var definition in settingDefinitions) + { + result.Add(definition.Name, new SettingValue(definition.Name, null)); + } - foreach (var provider in SettingValueProviderManager.Providers) + foreach (var provider in Enumerable.Reverse(SettingValueProviderManager.Providers)) { - foreach (var setting in settingDefinitions) + var settingValues = await provider.GetAllAsync(settingDefinitions.Where(x => !x.Providers.Any() || x.Providers.Contains(provider.Name)).ToArray()); + + var notNullValues = settingValues.Where(x => x.Value != null).ToList(); + foreach (var settingValue in notNullValues) { - var value = await provider.GetOrNullAsync(setting); - if (value != null) + var settingDefinition = settingDefinitions.First(x => x.Name == settingValue.Name); + if (settingDefinition.IsEncrypted) { - if (setting.IsEncrypted) - { - value = SettingEncryptionService.Decrypt(setting, value); - } + settingValue.Value = SettingEncryptionService.Decrypt(settingDefinition, settingValue.Value); + } - settingValues[setting.Name] = new SettingValue(setting.Name, value); + if (result.ContainsKey(settingValue.Name) && result[settingValue.Name].Value == null) + { + result[settingValue.Name].Value = settingValue.Value; } } + + settingDefinitions.RemoveAll(x => notNullValues.Any(v => v.Name == x.Name)); + } + + return result.Values.ToList(); + } + + public virtual async Task> GetAllAsync() + { + var settingValues = new List(); + var settingDefinitions = SettingDefinitionManager.GetAll(); + + foreach (var setting in settingDefinitions) + { + settingValues.Add(new SettingValue(setting.Name, await GetOrNullAsync(setting.Name))); } - return settingValues.Values.ToList(); + return settingValues; } protected virtual async Task GetOrNullValueFromProvidersAsync( diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProvider.cs index 91be8549ab..a286d8dba8 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/SettingValueProvider.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; namespace Volo.Abp.Settings @@ -15,5 +16,7 @@ namespace Volo.Abp.Settings } public abstract Task GetOrNullAsync(SettingDefinition setting); + + public abstract Task> GetAllAsync(SettingDefinition[] settings); } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/TenantSettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/TenantSettingValueProvider.cs index 4fa876ae80..6286356a04 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/TenantSettingValueProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/TenantSettingValueProvider.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Volo.Abp.MultiTenancy; namespace Volo.Abp.Settings @@ -21,5 +23,10 @@ namespace Volo.Abp.Settings { return await SettingStore.GetOrNullAsync(setting.Name, Name, CurrentTenant.Id?.ToString()); } + + public async override Task> GetAllAsync(SettingDefinition[] settings) + { + return await SettingStore.GetAllAsync(settings.Select(x => x.Name).ToArray(), Name, CurrentTenant.Id?.ToString()); + } } } diff --git a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/UserSettingValueProvider.cs b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/UserSettingValueProvider.cs index 0781b10433..8c337bbee4 100644 --- a/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/UserSettingValueProvider.cs +++ b/framework/src/Volo.Abp.Settings/Volo/Abp/Settings/UserSettingValueProvider.cs @@ -1,4 +1,6 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using Volo.Abp.Users; namespace Volo.Abp.Settings @@ -26,5 +28,15 @@ namespace Volo.Abp.Settings return await SettingStore.GetOrNullAsync(setting.Name, Name, CurrentUser.Id.ToString()); } + + public async override Task> GetAllAsync(SettingDefinition[] settings) + { + if (CurrentUser.Id == null) + { + return settings.Select(x => new SettingValue(x.Name, null)).ToList(); + } + + return await SettingStore.GetAllAsync(settings.Select(x => x.Name).ToArray(), Name, CurrentUser.Id.ToString()); + } } } 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 175e281716..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 @@ -14,5 +14,20 @@ namespace Volo.Abp.AspNetCore.Mvc.Authorization return Task.FromResult(result); } + + public Task IsGrantedAsync(string[] names, string providerName, string providerKey) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in names) + { + result.Result.Add(name, name == "TestPermission1" && + providerName == UserPermissionValueProvider.ProviderName && + providerKey == AuthTestController.FakeUserId.ToString() + ? PermissionGrantResult.Granted + : PermissionGrantResult.Prohibited); + } + + return Task.FromResult(result); + } } } diff --git a/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/TestSettingValueProvider.cs b/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/TestSettingValueProvider.cs index 2dbe1e5729..fbc2967d3b 100644 --- a/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/TestSettingValueProvider.cs +++ b/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/TestSettingValueProvider.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Volo.Abp.DependencyInjection; @@ -12,7 +13,7 @@ namespace Volo.Abp.Settings public string Name => ProviderName; - public TestSettingValueProvider() + public TestSettingValueProvider() { _values = new Dictionary(); } @@ -21,5 +22,10 @@ namespace Volo.Abp.Settings { return Task.FromResult(_values.GetOrDefault(setting.Name)); } + + public Task> GetAllAsync(SettingDefinition[] settings) + { + return Task.FromResult(settings.Select(x => new SettingValue(x.Name, _values.GetOrDefault(x.Name))).ToList()); + } } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGrantRepository.cs index 8c0beffd1a..7807cb4676 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IPermissionGrantRepository.cs @@ -20,5 +20,12 @@ namespace Volo.Abp.PermissionManagement string providerKey, CancellationToken cancellationToken = default ); + + Task> GetListAsync( + string[] names, + string providerName, + string providerKey, + CancellationToken cancellationToken = default + ); } -} \ No newline at end of file +} 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 49013954a2..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 @@ -1,10 +1,14 @@ using System; +using System.Linq; +using Volo.Abp.Text.Formatting; 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() @@ -19,7 +23,13 @@ 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 GetPermissionNameFormCacheKeyOrNull(string cacheKey) + { + var result = FormattedStringValueExtracter.Extract(cacheKey, CacheKeyFormat, true); + return result.IsMatch ? result.Matches.Last().Value : null; } } -} \ No newline at end of file +} 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 bdfdc38881..343e5f230d 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 @@ -53,9 +53,9 @@ namespace Volo.Abp.PermissionManagement } Logger.LogDebug($"Not found in the cache: {cacheKey}"); - + cacheItem = new PermissionGrantCacheItem(false); - + await SetCacheItemsAsync(providerName, providerKey, name, cacheItem); return cacheItem; @@ -68,7 +68,7 @@ namespace Volo.Abp.PermissionManagement PermissionGrantCacheItem currentCacheItem) { var permissions = PermissionDefinitionManager.GetPermissions(); - + Logger.LogDebug($"Getting all granted permissions from the repository for this provider name,key: {providerName},{providerKey}"); var grantedPermissionsHashSet = new HashSet( @@ -87,7 +87,7 @@ namespace Volo.Abp.PermissionManagement CalculateCacheKey(permission.Name, providerName, providerKey), new PermissionGrantCacheItem(isGranted)) ); - + if (permission.Name == currentName) { currentCacheItem.IsGranted = isGranted; @@ -95,13 +95,118 @@ namespace Volo.Abp.PermissionManagement } await Cache.SetManyAsync(cacheItems); - + + 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(GetPermissionNameFormCacheKeyOrNull(item.Key), + item.Value != null && 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; + } + + 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, + List notCacheKeys) + { + var permissions = PermissionDefinitionManager.GetPermissions().Where(x => notCacheKeys.Any(k => GetPermissionNameFormCacheKeyOrNull(k) == x.Name)).ToList(); + + Logger.LogDebug($"Getting not cache granted permissions from the repository for this provider name,key: {providerName},{providerKey}"); + + var grantedPermissionsHashSet = new HashSet( + (await PermissionGrantRepository.GetListAsync(notCacheKeys.Select(GetPermissionNameFormCacheKeyOrNull).ToArray(), providerName, providerKey)).Select(p => p.Name) + ); + + Logger.LogDebug($"Setting the cache items. Count: {permissions.Count}"); + + var cacheItems = new List>(); + + foreach (var permission in permissions) + { + var isGranted = grantedPermissionsHashSet.Contains(permission.Name); + + cacheItems.Add(new KeyValuePair( + CalculateCacheKey(permission.Name, providerName, providerKey), + new PermissionGrantCacheItem(isGranted)) + ); + } + + await Cache.SetManyAsync(cacheItems); + Logger.LogDebug($"Finished setting the cache items. Count: {permissions.Count}"); + + return cacheItems; } protected virtual string CalculateCacheKey(string name, string providerName, string providerKey) { return PermissionGrantCacheItem.CalculateCacheKey(name, providerName, providerKey); } + + protected virtual string GetPermissionNameFormCacheKeyOrNull(string key) + { + //TODO: throw ex when name is null? + return PermissionGrantCacheItem.GetPermissionNameFormCacheKeyOrNull(key); + } } -} \ No newline at end of file +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs index f3536605a2..1adb400307 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.EntityFrameworkCore/Volo/Abp/PermissionManagement/EntityFrameworkCore/EfCorePermissionGrantRepository.cs @@ -9,7 +9,7 @@ using Volo.Abp.EntityFrameworkCore; namespace Volo.Abp.PermissionManagement.EntityFrameworkCore { - public class EfCorePermissionGrantRepository : EfCoreRepository, + public class EfCorePermissionGrantRepository : EfCoreRepository, IPermissionGrantRepository { public EfCorePermissionGrantRepository(IDbContextProvider dbContextProvider) @@ -19,8 +19,8 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore } public virtual async Task FindAsync( - string name, - string providerName, + string name, + string providerName, string providerKey, CancellationToken cancellationToken = default) { @@ -44,5 +44,16 @@ namespace Volo.Abp.PermissionManagement.EntityFrameworkCore s.ProviderKey == providerKey ).ToListAsync(GetCancellationToken(cancellationToken)); } + + public virtual async Task> GetListAsync(string[] names, string providerName, string providerKey, + CancellationToken cancellationToken = default) + { + return await DbSet + .Where(s => + names.Contains(s.Name) && + s.ProviderName == providerName && + s.ProviderKey == providerKey + ).ToListAsync(GetCancellationToken(cancellationToken)); + } } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs index e51d9ecf7c..4e641f6016 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.MongoDB/Volo/Abp/PermissionManagement/MongoDb/MongoPermissionGrantRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; @@ -11,15 +12,15 @@ namespace Volo.Abp.PermissionManagement.MongoDB { public class MongoPermissionGrantRepository : MongoDbRepository, IPermissionGrantRepository { - public MongoPermissionGrantRepository(IMongoDbContextProvider dbContextProvider) + public MongoPermissionGrantRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) { } public virtual async Task FindAsync( - string name, - string providerName, + string name, + string providerName, string providerKey, CancellationToken cancellationToken = default) { @@ -33,7 +34,7 @@ namespace Volo.Abp.PermissionManagement.MongoDB } public virtual async Task> GetListAsync( - string providerName, + string providerName, string providerKey, CancellationToken cancellationToken = default) { @@ -43,5 +44,16 @@ namespace Volo.Abp.PermissionManagement.MongoDB s.ProviderKey == providerKey ).ToListAsync(GetCancellationToken(cancellationToken)); } + + public virtual async Task> GetListAsync(string[] names, string providerName, string providerKey, + CancellationToken cancellationToken = default) + { + return await GetMongoQueryable() + .Where(s => + names.Contains(s.Name) && + s.ProviderName == providerName && + s.ProviderKey == providerKey + ).ToListAsync(GetCancellationToken(cancellationToken)); + } } -} \ No newline at end of file +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionGrantCacheItem_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionGrantCacheItem_Tests.cs new file mode 100644 index 0000000000..d06c012cfa --- /dev/null +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionGrantCacheItem_Tests.cs @@ -0,0 +1,16 @@ +using Shouldly; +using Xunit; + +namespace Volo.Abp.PermissionManagement +{ + public class PermissionGrantCacheItem_Tests + { + [Fact] + public void GetPermissionNameFormCacheKeyOrNull() + { + var key = PermissionGrantCacheItem.CalculateCacheKey("aaa", "bbb", "ccc"); + PermissionGrantCacheItem.GetPermissionNameFormCacheKeyOrNull(key).ShouldBe("aaa"); + PermissionGrantCacheItem.GetPermissionNameFormCacheKeyOrNull("aaabbbccc").ShouldBeNull(); + } + } +} diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionStore_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionStore_Tests.cs index 965899ede9..ee0ef168c1 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionStore_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/PermissionStore_Tests.cs @@ -1,6 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Text; +using System.Linq; using System.Threading.Tasks; using Shouldly; using Volo.Abp.Authorization.Permissions; @@ -28,7 +26,19 @@ namespace Volo.Abp.PermissionManagement (await _permissionStore.IsGrantedAsync("MyPermission1NotExist", UserPermissionValueProvider.ProviderName, PermissionTestDataBuilder.User1Id.ToString())).ShouldBeFalse(); + } + + [Fact] + public async Task IsGranted_Multiple() + { + var result = await _permissionStore.IsGrantedAsync(new[] {"MyPermission1", "MyPermission1NotExist"}, + UserPermissionValueProvider.ProviderName, + PermissionTestDataBuilder.User1Id.ToString()); + + result.Result.Count.ShouldBe(2); + result.Result.FirstOrDefault(x => x.Key == "MyPermission1").Value.ShouldBe(PermissionGrantResult.Granted); + result.Result.FirstOrDefault(x => x.Key == "MyPermission1NotExist").Value.ShouldBe(PermissionGrantResult.Undefined); } } } diff --git a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionGrantRepository_Tests.cs b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionGrantRepository_Tests.cs index e27be7e426..6aca51987d 100644 --- a/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionGrantRepository_Tests.cs +++ b/modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/PermissionGrantRepository_Tests.cs @@ -32,5 +32,14 @@ namespace Volo.Abp.PermissionManagement permissionGrants.ShouldContain(p => p.Name == "MyPermission1"); } + + [Fact] + public async Task GetList_With_Names() + { + var permissionGrants = await PermissionGrantRepository.GetListAsync(new []{"MyPermission1", "MyPermission3"},UserPermissionValueProvider.ProviderName, PermissionTestDataBuilder.User1Id.ToString()); + + permissionGrants.ShouldContain(p => p.Name == "MyPermission1"); + permissionGrants.ShouldContain(p => p.Name == "MyPermission3"); + } } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingManagementStore.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingManagementStore.cs index eebdc69357..3c979039bb 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingManagementStore.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingManagementStore.cs @@ -10,8 +10,10 @@ namespace Volo.Abp.SettingManagement Task> GetListAsync(string providerName, string providerKey); + Task> GetListAsync(string[] names, string providerName, string providerKey); + Task SetAsync(string name, string value, string providerName, string providerKey); - + Task DeleteAsync(string name, string providerName, string providerKey); } -} \ No newline at end of file +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingRepository.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingRepository.cs index 6eeffae426..a1e40f3a14 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingRepository.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/ISettingRepository.cs @@ -10,5 +10,7 @@ namespace Volo.Abp.SettingManagement Task FindAsync(string name, string providerName, string providerKey); Task> GetListAsync(string providerName, string providerKey); + + Task> GetListAsync(string[] names, string providerName, string providerKey); } -} \ No newline at end of file +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs index 3511df204d..3b6b968e19 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingCacheItem.cs @@ -1,5 +1,7 @@ using System; +using System.Linq; using Volo.Abp.MultiTenancy; +using Volo.Abp.Text.Formatting; namespace Volo.Abp.SettingManagement { @@ -7,6 +9,8 @@ namespace Volo.Abp.SettingManagement [IgnoreMultiTenancy] public class SettingCacheItem { + private const string CacheKeyFormat = "pn:{0},pk:{1},n:{2}"; + public string Value { get; set; } public SettingCacheItem() @@ -21,7 +25,13 @@ namespace Volo.Abp.SettingManagement 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 GetSettingNameFormCacheKeyOrNull(string cacheKey) + { + var result = FormattedStringValueExtracter.Extract(cacheKey, CacheKeyFormat, true); + return result.IsMatch ? result.Matches.Last().Value : null; } } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs index a568184f0e..536bbaa532 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingManagementStore.cs @@ -118,9 +118,97 @@ namespace Volo.Abp.SettingManagement await Cache.SetManyAsync(cacheItems, considerUow: true); } + [UnitOfWork] + public async Task> GetListAsync(string[] names, string providerName, string providerKey) + { + Check.NotNullOrEmpty(names, nameof(names)); + + var result = new List(); + + if (names.Length == 1) + { + var name = names.First(); + result.Add(new SettingValue(name, (await GetCacheItemAsync(name, providerName, providerKey)).Value)); + return result; + } + + var cacheItems = await GetCacheItemsAsync(names, providerName, providerKey); + foreach (var item in cacheItems) + { + result.Add(new SettingValue(GetSettingNameFormCacheKeyOrNull(item.Key), item.Value?.Value)); + } + + return result; + } + + protected virtual async Task>> GetCacheItemsAsync(string[] names, string providerName, string providerKey) + { + var cacheKeys = names.Select(x => CalculateCacheKey(x, providerName, providerKey)).ToList(); + + var cacheItems = (await Cache.GetManyAsync(cacheKeys, considerUow: true)).ToList(); + + if (cacheItems.All(x => x.Value != null)) + { + return cacheItems; + } + + var notCacheKeys = cacheItems.Where(x => x.Value == null).Select(x => x.Key).ToList(); + + 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; + } + + private async Task>> SetCacheItemsAsync( + string providerName, + string providerKey, + List notCacheKeys) + { + var settingDefinitions = SettingDefinitionManager.GetAll().Where(x => notCacheKeys.Any(k => GetSettingNameFormCacheKeyOrNull(k) == x.Name)); + + var settingsDictionary = (await SettingRepository.GetListAsync(notCacheKeys.Select(GetSettingNameFormCacheKeyOrNull).ToArray(), providerName, providerKey)) + .ToDictionary(s => s.Name, s => s.Value); + + var cacheItems = new List>(); + + foreach (var settingDefinition in settingDefinitions) + { + var settingValue = settingsDictionary.GetOrDefault(settingDefinition.Name); + cacheItems.Add( + new KeyValuePair( + CalculateCacheKey(settingDefinition.Name, providerName, providerKey), + new SettingCacheItem(settingValue) + ) + ); + } + + await Cache.SetManyAsync(cacheItems, considerUow: true); + + return cacheItems; + } + + protected virtual string CalculateCacheKey(string name, string providerName, string providerKey) { return SettingCacheItem.CalculateCacheKey(name, providerName, providerKey); } + + protected virtual string GetSettingNameFormCacheKeyOrNull(string key) + { + //TODO: throw ex when name is null? + return SettingCacheItem.GetSettingNameFormCacheKeyOrNull(key); + } } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingStore.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingStore.cs index c38f915bf5..ab6bb185ca 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingStore.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Domain/Volo/Abp/SettingManagement/SettingStore.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Collections.Generic; +using System.Threading.Tasks; using Volo.Abp.DependencyInjection; using Volo.Abp.Settings; @@ -17,5 +18,10 @@ namespace Volo.Abp.SettingManagement { return ManagementStore.GetOrNullAsync(name, providerName, providerKey); } + + public virtual Task> GetAllAsync(string[] names, string providerName, string providerKey) + { + return ManagementStore.GetListAsync(names, providerName, providerKey); + } } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs index 66fe5e2eff..12999e5e1c 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.EntityFrameworkCore/Volo/Abp/SettingManagement/EntityFrameworkCore/EfCoreSettingRepository.cs @@ -30,5 +30,13 @@ namespace Volo.Abp.SettingManagement.EntityFrameworkCore s => s.ProviderName == providerName && s.ProviderKey == providerKey ).ToListAsync(); } + + public virtual async Task> GetListAsync(string[] names, string providerName, string providerKey) + { + return await DbSet + .Where( + s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey + ).ToListAsync(); + } } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs index 8ad74b914a..845e9b3a7b 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.MongoDB/Volo/Abp/SettingManagement/MongoDB/MongoSettingRepository.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using MongoDB.Driver; using MongoDB.Driver.Linq; @@ -25,5 +26,10 @@ namespace Volo.Abp.SettingManagement.MongoDB { return await GetMongoQueryable().Where(s => s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(); } + + public virtual async Task> GetListAsync(string[] names, string providerName, string providerKey) + { + return await GetMongoQueryable().Where(s => names.Contains(s.Name) && s.ProviderName == providerName && s.ProviderKey == providerKey).ToListAsync(); + } } -} \ No newline at end of file +} diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingRepository_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingRepository_Tests.cs index 5dad99a0ca..1d448f3154 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingRepository_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.TestBase/Volo/Abp/SettingManagement/SettingRepository_Tests.cs @@ -49,5 +49,14 @@ namespace Volo.Abp.SettingManagement settings.ShouldContain(s => s.Name == "MySetting1" && s.Value == "42"); settings.ShouldContain(s => s.Name == "MySetting2" && s.Value == "default-store-value"); } + + [Fact] + public async Task GetList_With_Names() + { + var settings = await SettingRepository.GetListAsync(new []{"MySetting1", "MySetting2"} ,GlobalSettingValueProvider.ProviderName, null); + settings.Any().ShouldBeTrue(); + settings.ShouldContain(s => s.Name == "MySetting1" && s.Value == "42"); + settings.ShouldContain(s => s.Name == "MySetting2" && s.Value == "default-store-value"); + } } } diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingCacheItem_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingCacheItem_Tests.cs new file mode 100644 index 0000000000..390851e08e --- /dev/null +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingCacheItem_Tests.cs @@ -0,0 +1,16 @@ +using Shouldly; +using Xunit; + +namespace Volo.Abp.SettingManagement +{ + public class SettingCacheItem_Tests + { + [Fact] + public void GetSettingNameFormCacheKeyOrNull() + { + var key = SettingCacheItem.CalculateCacheKey("aaa", "bbb", "ccc"); + SettingCacheItem.GetSettingNameFormCacheKeyOrNull(key).ShouldBe("aaa"); + SettingCacheItem.GetSettingNameFormCacheKeyOrNull("aaabbbccc").ShouldBeNull(); + } + } +} diff --git a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs index 7a405faf2d..1ccadef252 100644 --- a/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs +++ b/modules/setting-management/test/Volo.Abp.SettingManagement.Tests/Volo/Abp/SettingManagement/SettingManagementStore_Tests.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text; using System.Threading.Tasks; using Shouldly; @@ -94,5 +95,26 @@ namespace Volo.Abp.SettingManagement } } + [Fact] + public async Task GetListAsync() + { + var result = await _settingManagementStore.GetListAsync( + new[] + { + "MySetting1", + "MySetting2", + "MySetting3", + "notExistName" + }, + GlobalSettingValueProvider.ProviderName, + null); + + result.Count.ShouldBe(4); + + result.First(x => x.Name == "MySetting1").Value.ShouldBe("42"); + result.First(x => x.Name == "MySetting2").Value.ShouldBe("default-store-value"); + result.First(x => x.Name == "MySetting3").Value.ShouldBe(null); + result.First(x => x.Name == "notExistName").Value.ShouldBe(null); + } } }