From fccc3f20f6b19d7bdeaaff55f0bd4de277ba4151 Mon Sep 17 00:00:00 2001 From: maliming Date: Tue, 11 Nov 2025 19:53:48 +0800 Subject: [PATCH] Add resource-based permission value providers --- .../ResourcePermissionValueProvider.cs | 6 +- .../Authorization/AbpAuthorizationModule.cs | 4 + .../ResourcePermissionValueProviderManager.cs | 43 ++++++++++ .../RoleResourcePermissionValueProvider.cs | 79 +++++++++++++++++++ .../UserResourcePermissionValueProvider.cs | 46 +++++++++++ 5 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProviderManager.cs create mode 100644 framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/RoleResourcePermissionValueProvider.cs create mode 100644 framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/UserResourcePermissionValueProvider.cs diff --git a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProvider.cs index 9275502696..ff53f274ad 100644 --- a/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProvider.cs +++ b/framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProvider.cs @@ -7,11 +7,11 @@ public abstract class ResourcePermissionValueProvider : IResourcePermissionValue { public abstract string Name { get; } - protected IResourcePermissionStore PermissionStore { get; } + protected IResourcePermissionStore ResourcePermissionStore { get; } - protected ResourcePermissionValueProvider(IResourcePermissionStore permissionStore) + protected ResourcePermissionValueProvider(IResourcePermissionStore resourcePermissionStore) { - PermissionStore = permissionStore; + ResourcePermissionStore = resourcePermissionStore; } public abstract Task CheckAsync(ResourcePermissionValueCheckContext context); 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 d8226bdee5..ec2a2ddd82 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/AbpAuthorizationModule.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Volo.Abp.Authorization.Localization; using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.Permissions.Resources; using Volo.Abp.Localization; using Volo.Abp.Localization.ExceptionHandling; using Volo.Abp.Modularity; @@ -42,6 +43,9 @@ public class AbpAuthorizationModule : AbpModule options.ValueProviders.Add(); options.ValueProviders.Add(); options.ValueProviders.Add(); + + options.ResourceValueProviders.Add(); + options.ResourceValueProviders.Add(); }); Configure(options => diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProviderManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProviderManager.cs new file mode 100644 index 0000000000..628893397e --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/ResourcePermissionValueProviderManager.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class ResourcePermissionValueProviderManager : IResourcePermissionValueProviderManager, ISingletonDependency +{ + public IReadOnlyList ValueProviders => _lazyProviders.Value; + private readonly Lazy> _lazyProviders; + + protected AbpPermissionOptions Options { get; } + protected IServiceProvider ServiceProvider { get; } + + public ResourcePermissionValueProviderManager( + IServiceProvider serviceProvider, + IOptions options) + { + Options = options.Value; + ServiceProvider = serviceProvider; + + _lazyProviders = new Lazy>(GetProviders, true); + } + + protected virtual List GetProviders() + { + var providers = Options + .ValueProviders + .Select(type => (ServiceProvider.GetRequiredService(type) as IResourcePermissionValueProvider)!) + .ToList(); + + var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1); + if(multipleProviders != null) + { + throw new AbpException($"Duplicate permission value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}"); + } + + return providers; + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/RoleResourcePermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/RoleResourcePermissionValueProvider.cs new file mode 100644 index 0000000000..8a32da5f2c --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/RoleResourcePermissionValueProvider.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Security.Claims; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class RoleResourcePermissionValueProvider : ResourcePermissionValueProvider +{ + public const string ProviderName = "R"; + + public override string Name => ProviderName; + + public RoleResourcePermissionValueProvider(IResourcePermissionStore resourcePermissionStore) + : base(resourcePermissionStore) + { + + } + + public override async Task CheckAsync(ResourcePermissionValueCheckContext context) + { + var roles = context.Principal?.FindAll(AbpClaimTypes.Role).Select(c => c.Value).ToArray(); + + if (roles == null || !roles.Any()) + { + return PermissionGrantResult.Undefined; + } + + foreach (var role in roles.Distinct()) + { + if (await ResourcePermissionStore.IsGrantedAsync(context.Permission.Name, Name, role)) + { + return PermissionGrantResult.Granted; + } + } + + return PermissionGrantResult.Undefined; + } + + public override async Task CheckAsync(ResourcePermissionValuesCheckContext context) + { + var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToList(); + Check.NotNullOrEmpty(permissionNames, nameof(permissionNames)); + + 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.Distinct()) + { + var multipleResult = await ResourcePermissionStore.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; + } + + if (permissionNames.IsNullOrEmpty()) + { + break; + } + } + + return result; + } +} diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/UserResourcePermissionValueProvider.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/UserResourcePermissionValueProvider.cs new file mode 100644 index 0000000000..0597616709 --- /dev/null +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/Resources/UserResourcePermissionValueProvider.cs @@ -0,0 +1,46 @@ +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Security.Claims; + +namespace Volo.Abp.Authorization.Permissions.Resources; + +public class UserResourcePermissionValueProvider : ResourcePermissionValueProvider +{ + public const string ProviderName = "U"; + + public override string Name => ProviderName; + + public UserResourcePermissionValueProvider(IResourcePermissionStore resourcePermissionStore) + : base(resourcePermissionStore) + { + + } + + public override async Task CheckAsync(ResourcePermissionValueCheckContext context) + { + var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value; + + if (userId == null) + { + return PermissionGrantResult.Undefined; + } + + return await ResourcePermissionStore.IsGrantedAsync(context.Permission.Name, Name, userId) + ? PermissionGrantResult.Granted + : PermissionGrantResult.Undefined; + } + + public override async Task CheckAsync(ResourcePermissionValuesCheckContext context) + { + var permissionNames = context.Permissions.Select(x => x.Name).Distinct().ToArray(); + Check.NotNullOrEmpty(permissionNames, nameof(permissionNames)); + + var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value; + if (userId == null) + { + return new MultiplePermissionGrantResult(permissionNames); + } + + return await ResourcePermissionStore.IsGrantedAsync(permissionNames, Name, userId); + } +}