From 90bf895cacc6f9c9fc7677429e2149b58d7f9ecb Mon Sep 17 00:00:00 2001 From: maliming Date: Thu, 13 Nov 2025 14:26:44 +0800 Subject: [PATCH] Implement `ResourcePermissionManager`. --- ...ermissionManagementDomainIdentityModule.cs | 5 + ...oleResourcePermissionManagementProvider.cs | 80 ++++++ ...serResourcePermissionManagementProvider.cs | 22 ++ .../IResourcePermissionManagementProvider.cs | 34 +++ .../IResourcePermissionManager.cs | 30 +- .../PermissionManagementOptions.cs | 3 + .../ResourcePermissionManagementProvider.cs | 87 ++++++ .../ResourcePermissionManager.cs | 257 ++++++++++++++++++ 8 files changed, 503 insertions(+), 15 deletions(-) create mode 100644 modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionManagementProvider.cs create mode 100644 modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionManagementProvider.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManagementProvider.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider.cs create mode 100644 modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManager.cs diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/AbpPermissionManagementDomainIdentityModule.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/AbpPermissionManagementDomainIdentityModule.cs index 973577ccff..1eec9d44c8 100644 --- a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/AbpPermissionManagementDomainIdentityModule.cs +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/AbpPermissionManagementDomainIdentityModule.cs @@ -1,4 +1,5 @@ using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; using Volo.Abp.Identity; using Volo.Abp.Modularity; using Volo.Abp.Users; @@ -18,10 +19,14 @@ public class AbpPermissionManagementDomainIdentityModule : AbpModule { options.ManagementProviders.Add(); options.ManagementProviders.Add(); + options.ResourceManagementProviders.Add(); + options.ResourceManagementProviders.Add(); //TODO: Can we prevent duplication of permission names without breaking the design and making the system complicated options.ProviderPolicies[UserPermissionValueProvider.ProviderName] = "AbpIdentity.Users.ManagePermissions"; options.ProviderPolicies[RolePermissionValueProvider.ProviderName] = "AbpIdentity.Roles.ManagePermissions"; + options.ProviderPolicies[UserResourcePermissionValueProvider.ProviderName] = "AbpIdentity.Users.ManagePermissions"; + options.ProviderPolicies[RoleResourcePermissionValueProvider.ProviderName] = "AbpIdentity.Roles.ManagePermissions"; }); } } diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionManagementProvider.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionManagementProvider.cs new file mode 100644 index 0000000000..8b77face53 --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionManagementProvider.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Guids; +using Volo.Abp.Identity; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement.Identity; + +public class RoleResourcePermissionManagementProvider : ResourcePermissionManagementProvider +{ + public override string Name => RoleResourcePermissionValueProvider.ProviderName; + + protected IUserRoleFinder UserRoleFinder { get; } + + public RoleResourcePermissionManagementProvider( + IResourcePermissionGrantRepository resourcepPrmissionGrantRepository, + IGuidGenerator guidGenerator, + ICurrentTenant currentTenant, + IUserRoleFinder userRoleFinder) + : base( + resourcepPrmissionGrantRepository, + guidGenerator, + currentTenant) + { + UserRoleFinder = userRoleFinder; + } + + public override async Task CheckAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey) + { + var multipleGrantInfo = await CheckAsync(new[] { name }, resourceName, resourceKey, providerName, providerKey); + + return multipleGrantInfo.Result.Values.First(); + } + + public override async Task CheckAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey) + { + using (ResourcePermissionGrantRepository.DisableTracking()) + { + var multiplePermissionValueProviderGrantInfo = new MultiplePermissionValueProviderGrantInfo(names); + var resourcePermissionGrants = new List(); + + if (providerName == Name) + { + resourcePermissionGrants.AddRange(await ResourcePermissionGrantRepository.GetListAsync(names, resourceName, resourceKey, providerName, providerKey)); + } + + if (providerName == UserResourcePermissionValueProvider.ProviderName) + { + var userId = Guid.Parse(providerKey); + var roleNames = await UserRoleFinder.GetRoleNamesAsync(userId); + + foreach (var roleName in roleNames) + { + resourcePermissionGrants.AddRange(await ResourcePermissionGrantRepository.GetListAsync(names, resourceName, resourceKey, Name, roleName)); + } + } + + resourcePermissionGrants = resourcePermissionGrants.Distinct().ToList(); + if (!resourcePermissionGrants.Any()) + { + return multiplePermissionValueProviderGrantInfo; + } + + foreach (var permissionName in names) + { + var resourcePermissionGrant = resourcePermissionGrants.FirstOrDefault(x => x.Name == permissionName); + if (resourcePermissionGrant != null) + { + multiplePermissionValueProviderGrantInfo.Result[permissionName] = new PermissionValueProviderGrantInfo(true, resourcePermissionGrant.ProviderKey); + } + } + + return multiplePermissionValueProviderGrantInfo; + } + } +} diff --git a/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionManagementProvider.cs b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionManagementProvider.cs new file mode 100644 index 0000000000..ef165d422d --- /dev/null +++ b/modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionManagementProvider.cs @@ -0,0 +1,22 @@ +using Volo.Abp.Authorization.Permissions.Resources; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement.Identity; + +public class UserResourcePermissionManagementProvider : ResourcePermissionManagementProvider +{ + public override string Name => UserResourcePermissionValueProvider.ProviderName; + + public UserResourcePermissionManagementProvider( + IResourcePermissionGrantRepository resourcePermissionGrantRepository, + IGuidGenerator guidGenerator, + ICurrentTenant currentTenant) + : base( + resourcePermissionGrantRepository, + guidGenerator, + currentTenant) + { + + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManagementProvider.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManagementProvider.cs new file mode 100644 index 0000000000..e5f1fe78ac --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManagementProvider.cs @@ -0,0 +1,34 @@ +using System.Threading.Tasks; +using JetBrains.Annotations; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.PermissionManagement; + +public interface IResourcePermissionManagementProvider : ISingletonDependency //TODO: Consider to remove this pre-assumption +{ + string Name { get; } + + Task CheckAsync( + [NotNull] string name, + [NotNull] string resourceName, + [NotNull] string resourceKey, + [NotNull] string providerName, + [NotNull] string providerKey + ); + + Task CheckAsync( + [NotNull] string[] names, + [NotNull] string resourceName, + [NotNull] string resourceKey, + [NotNull] string providerName, + [NotNull] string providerKey + ); + + Task SetAsync( + [NotNull] string name, + [NotNull] string resourceName, + [NotNull] string resourceKey, + [NotNull] string providerKey, + bool isGranted + ); +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManager.cs index f58fcdc584..0ca47706d5 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManager.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManager.cs @@ -7,33 +7,33 @@ public interface IResourcePermissionManager { Task GetAsync( string permissionName, - string providerName, - string providerKey, string resourceName, - string resourceKey + string resourceKey, + string providerName, + string providerKey ); - + Task GetAsync( string[] permissionNames, - string provideName, - string providerKey, string resourceName, - string resourceKey + string resourceKey, + string providerName, + string providerKey ); - + Task> GetAllAsync( - string providerName, - string providerKey, string resourceName, - string resourceKey + string resourceKey, + string providerName, + string providerKey ); - + Task SetAsync( string permissionName, - string providerName, - string providerKey, string resourceName, string resourceKey, + string providerName, + string providerKey, bool isGranted ); -} \ No newline at end of file +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs index 489ae26e3d..e917a3fea6 100644 --- a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/PermissionManagementOptions.cs @@ -7,6 +7,8 @@ public class PermissionManagementOptions { public ITypeList ManagementProviders { get; } + public ITypeList ResourceManagementProviders { get; } + public Dictionary ProviderPolicies { get; } /// @@ -22,6 +24,7 @@ public class PermissionManagementOptions public PermissionManagementOptions() { ManagementProviders = new TypeList(); + ResourceManagementProviders = new TypeList(); ProviderPolicies = new Dictionary(); } } diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider.cs new file mode 100644 index 0000000000..3344995b07 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider.cs @@ -0,0 +1,87 @@ +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; + +namespace Volo.Abp.PermissionManagement; + +public abstract class ResourcePermissionManagementProvider : IResourcePermissionManagementProvider +{ + public abstract string Name { get; } + + protected IResourcePermissionGrantRepository ResourcePermissionGrantRepository { get; } + + protected IGuidGenerator GuidGenerator { get; } + + protected ICurrentTenant CurrentTenant { get; } + + protected ResourcePermissionManagementProvider( + IResourcePermissionGrantRepository resourcePermissionGrantRepository, + IGuidGenerator guidGenerator, + ICurrentTenant currentTenant) + { + ResourcePermissionGrantRepository = resourcePermissionGrantRepository; + GuidGenerator = guidGenerator; + CurrentTenant = currentTenant; + } + + public virtual async Task CheckAsync(string name, string resourceName,string resourceKey, string providerName, string providerKey) + { + var multiplePermissionValueProviderGrantInfo = await CheckAsync(new[] { name }, resourceName, resourceKey, providerName, providerKey); + + return multiplePermissionValueProviderGrantInfo.Result.First().Value; + } + + public virtual async Task CheckAsync(string[] names, string resourceName, string resourceKey, string providerName, string providerKey) + { + using (ResourcePermissionGrantRepository.DisableTracking()) + { + var multiplePermissionValueProviderGrantInfo = new MultiplePermissionValueProviderGrantInfo(names); + if (providerName != Name) + { + return multiplePermissionValueProviderGrantInfo; + } + + var resourcePermissionGrants = await ResourcePermissionGrantRepository.GetListAsync(names, resourceName, resourceKey, providerName, providerKey); + + foreach (var permissionName in names) + { + var isGrant = resourcePermissionGrants.Any(x => x.Name == permissionName); + multiplePermissionValueProviderGrantInfo.Result[permissionName] = new PermissionValueProviderGrantInfo(isGrant, providerKey); + } + + return multiplePermissionValueProviderGrantInfo; + } + } + + public virtual Task SetAsync(string name, string resourceName,string resourceKey, string providerKey, bool isGranted) + { + return isGranted + ? GrantAsync(name, resourceName, resourceKey, providerKey) + : RevokeAsync(name, resourceName, resourceKey, providerKey); + } + + protected virtual async Task GrantAsync(string name, string resourceName, string resourceKey, string providerKey) + { + var resourcePermissionGrants = await ResourcePermissionGrantRepository.FindAsync(name, resourceName, resourceKey, Name, providerKey); + if (resourcePermissionGrants != null) + { + return; + } + + resourcePermissionGrants = new ResourcePermissionGrant(GuidGenerator.Create(), name, resourceName, resourceKey, Name, providerKey, CurrentTenant.Id); + await ResourcePermissionGrantRepository.InsertAsync(resourcePermissionGrants, true); + } + + protected virtual async Task RevokeAsync(string name, string resourceName,string resourceKey, string providerKey) + { + var resourcePermissionGrants = await ResourcePermissionGrantRepository.FindAsync(name, resourceName, resourceKey, Name, providerKey); + if (resourcePermissionGrants == null) + { + return; + } + + await ResourcePermissionGrantRepository.DeleteAsync(resourcePermissionGrants, true); + } +} diff --git a/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManager.cs b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManager.cs new file mode 100644 index 0000000000..f22ebb40e3 --- /dev/null +++ b/modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManager.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Guids; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SimpleStateChecking; + +namespace Volo.Abp.PermissionManagement; + +public class ResourcePermissionManager : IResourcePermissionManager, ISingletonDependency +{ + protected IResourcePermissionGrantRepository ResourcePermissionGrantRepository { get; } + + protected IPermissionDefinitionManager PermissionDefinitionManager { get; } + + protected ISimpleStateCheckerManager SimpleStateCheckerManager { get; } + + protected IGuidGenerator GuidGenerator { get; } + + protected ICurrentTenant CurrentTenant { get; } + + protected IReadOnlyList ManagementProviders => _lazyProviders.Value; + + protected PermissionManagementOptions Options { get; } + + protected IDistributedCache Cache { get; } + + private readonly Lazy> _lazyProviders; + + public ResourcePermissionManager( + IPermissionDefinitionManager permissionDefinitionManager, + ISimpleStateCheckerManager simpleStateCheckerManager, + IResourcePermissionGrantRepository resourcePermissionGrantRepository, + IServiceProvider serviceProvider, + IGuidGenerator guidGenerator, + IOptions options, + ICurrentTenant currentTenant, + IDistributedCache cache) + { + GuidGenerator = guidGenerator; + CurrentTenant = currentTenant; + Cache = cache; + SimpleStateCheckerManager = simpleStateCheckerManager; + ResourcePermissionGrantRepository = resourcePermissionGrantRepository; + PermissionDefinitionManager = permissionDefinitionManager; + Options = options.Value; + + _lazyProviders = new Lazy>( + () => Options + .ResourceManagementProviders + .Select(c => serviceProvider.GetRequiredService(c) as IResourcePermissionManagementProvider) + .ToList(), + true + ); + } + + public virtual async Task GetAsync(string permissionName, string resourceName, string resourceKey, string providerName, string providerKey) + { + var permission = await PermissionDefinitionManager.GetResourcePermissionOrNullAsync(permissionName); + if (permission == null) + { + return new PermissionWithGrantedProviders(permissionName, false); + } + + return await GetInternalAsync( + permission, + resourceName, + resourceKey, + providerName, + providerKey + ); + } + + public virtual async Task GetAsync(string[] permissionNames, string resourceName, string resourceKey, string providerName, string providerKey) + { + var permissions = new List(); + var undefinedPermissions = new List(); + + foreach (var permissionName in permissionNames) + { + var permission = await PermissionDefinitionManager.GetResourcePermissionOrNullAsync(permissionName); + if (permission != null) + { + permissions.Add(permission); + } + else + { + undefinedPermissions.Add(permissionName); + } + } + + if (!permissions.Any()) + { + return new MultiplePermissionWithGrantedProviders(undefinedPermissions.ToArray()); + } + + var result = await GetInternalAsync( + permissions.ToArray(), + resourceName, + resourceKey, + providerName, + providerKey + ); + + foreach (var undefinedPermission in undefinedPermissions) + { + result.Result.Add(new PermissionWithGrantedProviders(undefinedPermission, false)); + } + + return result; + } + + public virtual async Task> GetAllAsync(string resourceName, string resourceKey, string providerName, string providerKey) + { + var permissionDefinitions = (await PermissionDefinitionManager.GetResourcePermissionsAsync()).ToArray(); + + var multiplePermissionWithGrantedProviders = await GetInternalAsync(permissionDefinitions, resourceName, resourceKey, providerName, providerKey); + + return multiplePermissionWithGrantedProviders.Result; + } + + public virtual async Task SetAsync(string permissionName, string resourceName, string resourceKey, string providerName, string providerKey, bool isGranted) + { + var permission = await PermissionDefinitionManager.GetResourcePermissionOrNullAsync(permissionName); + if (permission == null) + { + /* Silently ignore undefined permissions, + maybe they were removed from dynamic permission definition store */ + return; + } + + if (!permission.IsEnabled || !await SimpleStateCheckerManager.IsEnabledAsync(permission)) + { + //TODO: BusinessException + throw new ApplicationException($"The resource permission named '{permission.Name}' is disabled!"); + } + + if (permission.Providers.Any() && !permission.Providers.Contains(providerName)) + { + //TODO: BusinessException + throw new ApplicationException($"The resource permission named '{permission.Name}' has not compatible with the provider named '{providerName}'"); + } + + if (!permission.MultiTenancySide.HasFlag(CurrentTenant.GetMultiTenancySide())) + { + //TODO: BusinessException + throw new ApplicationException($"The resource permission named '{permission.Name}' has multitenancy side '{permission.MultiTenancySide}' which is not compatible with the current multitenancy side '{CurrentTenant.GetMultiTenancySide()}'"); + } + + var currentGrantInfo = await GetInternalAsync(permission, resourceName, resourceKey, providerName, providerKey); + if (currentGrantInfo.IsGranted == isGranted) + { + return; + } + + var provider = ManagementProviders.FirstOrDefault(m => m.Name == providerName); + if (provider == null) + { + //TODO: BusinessException + throw new AbpException("Unknown permission management provider: " + providerName); + } + + await provider.SetAsync(permissionName, resourceName, resourceKey, providerKey, isGranted); + } + + public virtual async Task UpdateProviderKeyAsync(ResourcePermissionGrant resourcePermissionGrant, string resourceName, string resourceKey, string providerKey) + { + using (CurrentTenant.Change(resourcePermissionGrant.TenantId)) + { + //Invalidating the cache for the old key + await Cache.RemoveAsync( + ResourcePermissionGrantCacheItem.CalculateCacheKey( + resourcePermissionGrant.Name, + resourcePermissionGrant.ResourceName, + resourcePermissionGrant.ResourceKey, + resourcePermissionGrant.ProviderName, + resourcePermissionGrant.ProviderKey + ) + ); + } + + resourcePermissionGrant.ProviderKey = providerKey; + return await ResourcePermissionGrantRepository.UpdateAsync(resourcePermissionGrant, true); + } + + public virtual async Task DeleteAsync(string providerName, string resourceName, string resourceKey, string providerKey) + { + var permissionGrants = await ResourcePermissionGrantRepository.GetListAsync(providerName, resourceName, resourceKey, providerKey); + foreach (var permissionGrant in permissionGrants) + { + await ResourcePermissionGrantRepository.DeleteAsync(permissionGrant, true); + } + } + + protected virtual async Task GetInternalAsync(PermissionDefinition permission, string resourceName, string resourceKey, string providerName, string providerKey) + { + var multiplePermissionWithGrantedProviders = await GetInternalAsync( + new[] { permission }, + resourceName, + resourceKey, + providerName, + providerKey + ); + + return multiplePermissionWithGrantedProviders.Result.First(); + } + + protected virtual async Task GetInternalAsync(PermissionDefinition[] permissions, string resourceName, string resourceKey, string providerName, string providerKey) + { + var permissionNames = permissions.Select(x => x.Name).ToArray(); + var multiplePermissionWithGrantedProviders = new MultiplePermissionWithGrantedProviders(permissionNames); + + var neededCheckPermissions = new List(); + + foreach (var permission in permissions + .Where(x => x.IsEnabled) + .Where(x => x.MultiTenancySide.HasFlag(CurrentTenant.GetMultiTenancySide())) + .Where(x => !x.Providers.Any() || x.Providers.Contains(providerName))) + { + if (await SimpleStateCheckerManager.IsEnabledAsync(permission)) + { + neededCheckPermissions.Add(permission); + } + } + + if (!neededCheckPermissions.Any()) + { + return multiplePermissionWithGrantedProviders; + } + + foreach (var provider in ManagementProviders) + { + permissionNames = neededCheckPermissions.Select(x => x.Name).ToArray(); + var multiplePermissionValueProviderGrantInfo = await provider.CheckAsync(permissionNames, resourceName, resourceKey, providerName, providerKey); + + foreach (var providerResultDict in multiplePermissionValueProviderGrantInfo.Result) + { + if (providerResultDict.Value.IsGranted) + { + var permissionWithGrantedProvider = multiplePermissionWithGrantedProviders.Result + .First(x => x.Name == providerResultDict.Key); + + permissionWithGrantedProvider.IsGranted = true; + permissionWithGrantedProvider.Providers.Add(new PermissionValueProviderInfo(provider.Name, providerResultDict.Value.ProviderKey)); + } + } + } + + return multiplePermissionWithGrantedProviders; + } +}