Browse Source

Implement resource-based permission management with new methods and classes

pull/24374/head
maliming 11 months ago
parent
commit
a2d39ad8b3
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 13
      framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs
  2. 7
      framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs
  3. 14
      framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs
  4. 73
      framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs
  5. 31
      framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs
  6. 21
      framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/ResourcePermissionRequirement.cs
  7. 8
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs
  8. 8
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs
  9. 19
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs
  10. 44
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs
  11. 32
      framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs
  12. 13
      framework/src/Volo.Abp.Ddd.Domain/Microsoft/Extensions/DependencyInjection/EntityResourcePermissionAuthorizationExtensions.cs
  13. 30
      framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Authorization/Permissions/Resources/EntityResourcePermissionRequirementHandler.cs

13
framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionContext.cs

@ -1,5 +1,7 @@
using System;
using JetBrains.Annotations;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Authorization.Permissions;
@ -46,4 +48,15 @@ public interface IPermissionDefinitionContext
/// <param name="name">Name of the permission</param>
/// </summary>
PermissionDefinition? GetPermissionOrNull(string name);
PermissionDefinition AddResourcePermission(
string name,
string resourceName,
ILocalizableString? displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true);
PermissionDefinition? GetResourcePermissionOrNull([NotNull] string name);
void RemoveResourcePermission([NotNull] string name);
}

7
framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/IPermissionDefinitionManager.cs

@ -11,7 +11,14 @@ public interface IPermissionDefinitionManager
Task<PermissionDefinition?> GetOrNullAsync([NotNull] string name);
[ItemNotNull]
Task<PermissionDefinition> GetResourcePermissionAsync([NotNull] string name);
Task<PermissionDefinition?> GetResourcePermissionOrNullAsync([NotNull] string name);
Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync();
Task<IReadOnlyList<PermissionDefinition>> GetResourcePermissionsAsync();
Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync();
}

14
framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinition.cs

@ -83,13 +83,22 @@ public class PermissionDefinition :
protected internal PermissionDefinition(
[NotNull] string name,
string? resourceName = null,
string resourceName,
ILocalizableString? displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
: this(name, displayName, multiTenancySide, isEnabled)
{
ResourceName = Check.NotNull(resourceName, nameof(resourceName));
}
protected internal PermissionDefinition(
[NotNull] string name,
ILocalizableString? displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
Name = Check.NotNull(name, nameof(name));
ResourceName = resourceName;
DisplayName = displayName ?? new FixedLocalizableString(name);
MultiTenancySide = multiTenancySide;
IsEnabled = isEnabled;
@ -108,7 +117,6 @@ public class PermissionDefinition :
{
var child = new PermissionDefinition(
name,
null,
displayName,
multiTenancySide,
isEnabled)

73
framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionDefinitionContext.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.Authorization.Permissions;
@ -11,17 +12,20 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext
public Dictionary<string, PermissionGroupDefinition> Groups { get; }
public Dictionary<string, PermissionDefinition> ResourcePermissions { get; }
internal IPermissionDefinitionProvider? CurrentProvider { get; set; }
public static class KnownPropertyNames
{
public const string CurrentProviderName = "_CurrentProviderName";
}
public PermissionDefinitionContext(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
Groups = new Dictionary<string, PermissionGroupDefinition>();
ResourcePermissions = new Dictionary<string, PermissionDefinition>();
}
public virtual PermissionGroupDefinition AddGroup(
@ -43,7 +47,7 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext
}
Groups[name] = group;
return group;
}
@ -51,37 +55,23 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext
public virtual PermissionGroupDefinition GetGroup([NotNull] string name)
{
var group = GetGroupOrNull(name);
if (group == null)
{
throw new AbpException($"Could not find a permission definition group with the given name: {name}");
}
return group;
return group ?? throw new AbpException($"Could not find a permission definition group with the given name: {name}");
}
public virtual PermissionGroupDefinition? GetGroupOrNull([NotNull] string name)
{
Check.NotNull(name, nameof(name));
if (!Groups.ContainsKey(name))
{
return null;
}
return Groups[name];
return Groups.GetOrDefault(name);
}
public virtual void RemoveGroup(string name)
{
Check.NotNull(name, nameof(name));
if (!Groups.ContainsKey(name))
if (!Groups.Remove(name))
{
throw new AbpException($"Not found permission group with name: {name}");
}
Groups.Remove(name);
}
public virtual PermissionDefinition? GetPermissionOrNull([NotNull] string name)
@ -100,4 +90,49 @@ public class PermissionDefinitionContext : IPermissionDefinitionContext
return null;
}
public virtual PermissionDefinition AddResourcePermission(
string name,
string resourceName,
ILocalizableString? displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
Check.NotNull(name, nameof(name));
if (ResourcePermissions.ContainsKey(name))
{
throw new AbpException($"There is already an existing resource permission with name: {name}");
}
var permission = new PermissionDefinition(
name,
resourceName,
displayName,
multiTenancySide,
isEnabled)
{
[KnownPropertyNames.CurrentProviderName] = CurrentProvider?.GetType().FullName
};
ResourcePermissions[name] = permission;
return permission;
}
public virtual PermissionDefinition? GetResourcePermissionOrNull([NotNull] string name)
{
Check.NotNull(name, nameof(name));
return ResourcePermissions.GetOrDefault(name);
}
public virtual void RemoveResourcePermission([NotNull] string name)
{
Check.NotNull(name, nameof(name));
if (!ResourcePermissions.Remove(name))
{
throw new AbpException($"Not found resource permission with name: {name}");
}
}
}

31
framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/Permissions/PermissionGroupDefinition.cs

@ -53,40 +53,9 @@ public class PermissionGroupDefinition : ICanAddChildPermission
ILocalizableString? displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
return AddPermission(
name,
null,
displayName,
multiTenancySide,
isEnabled);
}
public virtual PermissionDefinition AddResourcePermission(
[NotNull] string name,
[NotNull] string resourceName,
ILocalizableString? displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
return AddPermission(
name,
resourceName,
displayName,
multiTenancySide,
isEnabled);
}
protected virtual PermissionDefinition AddPermission(
[NotNull] string name,
string? resourceName,
ILocalizableString? displayName = null,
MultiTenancySides multiTenancySide = MultiTenancySides.Both,
bool isEnabled = true)
{
var permission = new PermissionDefinition(
name,
resourceName,
displayName,
multiTenancySide,
isEnabled

21
framework/src/Volo.Abp.Authorization.Abstractions/Volo/Abp/Authorization/ResourcePermissionRequirement.cs

@ -0,0 +1,21 @@
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authorization;
namespace Volo.Abp.Authorization;
public class ResourcePermissionRequirement : IAuthorizationRequirement
{
public string PermissionName { get; }
public ResourcePermissionRequirement([NotNull] string permissionName)
{
Check.NotNull(permissionName, nameof(permissionName));
PermissionName = permissionName;
}
public override string ToString()
{
return $"ResourcePermissionRequirement: {PermissionName}";
}
}

8
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IDynamicPermissionDefinitionStore.cs

@ -8,6 +8,10 @@ public interface IDynamicPermissionDefinitionStore
Task<PermissionDefinition?> GetOrNullAsync(string name);
Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync();
Task<PermissionDefinition?> GetResourcePermissionOrNullAsync(string name);
Task<IReadOnlyList<PermissionDefinition>> GetResourcePermissionsAsync();
Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync();
}
}

8
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/IStaticPermissionDefinitionStore.cs

@ -8,6 +8,10 @@ public interface IStaticPermissionDefinitionStore
Task<PermissionDefinition?> GetOrNullAsync(string name);
Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync();
Task<PermissionDefinition?> GetResourcePermissionOrNullAsync(string name);
Task<IReadOnlyList<PermissionDefinition>> GetResourcePermissionsAsync();
Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync();
}
}

19
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/NullDynamicPermissionDefinitionStore.cs

@ -9,10 +9,15 @@ namespace Volo.Abp.Authorization.Permissions;
public class NullDynamicPermissionDefinitionStore : IDynamicPermissionDefinitionStore, ISingletonDependency
{
private readonly static Task<PermissionDefinition?> CachedPermissionResult = Task.FromResult((PermissionDefinition?)null);
private readonly static Task<IReadOnlyList<PermissionDefinition>> CachedPermissionsResult =
Task.FromResult((IReadOnlyList<PermissionDefinition>)Array.Empty<PermissionDefinition>().ToImmutableList());
private readonly static Task<PermissionDefinition?> CachedResourcePermissionResult = Task.FromResult((PermissionDefinition?)null);
private readonly static Task<IReadOnlyList<PermissionDefinition>> CachedResourcePermissionsResult =
Task.FromResult((IReadOnlyList<PermissionDefinition>)Array.Empty<PermissionDefinition>().ToImmutableList());
private readonly static Task<IReadOnlyList<PermissionGroupDefinition>> CachedGroupsResult =
Task.FromResult((IReadOnlyList<PermissionGroupDefinition>)Array.Empty<PermissionGroupDefinition>().ToImmutableList());
@ -26,8 +31,18 @@ public class NullDynamicPermissionDefinitionStore : IDynamicPermissionDefinition
return CachedPermissionsResult;
}
public Task<PermissionDefinition?> GetResourcePermissionOrNullAsync(string name)
{
return CachedResourcePermissionResult;
}
public Task<IReadOnlyList<PermissionDefinition>> GetResourcePermissionsAsync()
{
return CachedResourcePermissionsResult;
}
public Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
{
return CachedGroupsResult;
}
}
}

44
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionDefinitionManager.cs

@ -34,17 +34,36 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransi
{
Check.NotNull(name, nameof(name));
return await _staticStore.GetOrNullAsync(name) ??
return await _staticStore.GetOrNullAsync(name) ??
await _dynamicStore.GetOrNullAsync(name);
}
public virtual async Task<PermissionDefinition> GetResourcePermissionAsync(string name)
{
var permission = await GetResourcePermissionOrNullAsync(name);
if (permission == null)
{
throw new AbpException("Undefined permission: " + name);
}
return permission;
}
public virtual async Task<PermissionDefinition?> GetResourcePermissionOrNullAsync(string name)
{
Check.NotNull(name, nameof(name));
return await _staticStore.GetResourcePermissionOrNullAsync(name) ??
await _dynamicStore.GetResourcePermissionOrNullAsync(name);
}
public virtual async Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync()
{
var staticPermissions = await _staticStore.GetPermissionsAsync();
var staticPermissionNames = staticPermissions
.Select(p => p.Name)
.ToImmutableHashSet();
var dynamicPermissions = await _dynamicStore.GetPermissionsAsync();
/* We prefer static permissions over dynamics */
@ -53,13 +72,28 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransi
).ToImmutableList();
}
public async Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
public virtual async Task<IReadOnlyList<PermissionDefinition>> GetResourcePermissionsAsync()
{
var staticResourcePermissions = await _staticStore.GetResourcePermissionsAsync();
var staticResourcePermissionNames = staticResourcePermissions
.Select(p => p.Name)
.ToImmutableHashSet();
var dynamicResourcePermissions = await _dynamicStore.GetResourcePermissionsAsync();
/* We prefer static permissions over dynamics */
return staticResourcePermissions.Concat(
dynamicResourcePermissions.Where(d => !staticResourcePermissionNames.Contains(d.Name))
).ToImmutableList();
}
public virtual async Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
{
var staticGroups = await _staticStore.GetGroupsAsync();
var staticGroupNames = staticGroups
.Select(p => p.Name)
.ToImmutableHashSet();
var dynamicGroups = await _dynamicStore.GetGroupsAsync();
/* We prefer static groups over dynamics */
@ -67,4 +101,4 @@ public class PermissionDefinitionManager : IPermissionDefinitionManager, ITransi
dynamicGroups.Where(d => !staticGroupNames.Contains(d.Name))
).ToImmutableList();
}
}
}

32
framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/StaticPermissionDefinitionStore.cs

@ -11,12 +11,14 @@ namespace Volo.Abp.Authorization.Permissions;
public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore, ISingletonDependency
{
protected IDictionary<string, PermissionGroupDefinition> PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value;
private readonly Lazy<Dictionary<string, PermissionGroupDefinition>> _lazyPermissionGroupDefinitions;
protected IDictionary<string, PermissionGroupDefinition> PermissionGroupDefinitions => _lazyPermissionGroupDefinitions.Value.Item1;
private readonly Lazy<(Dictionary<string, PermissionGroupDefinition>, Dictionary<string, PermissionDefinition>)> _lazyPermissionGroupDefinitions;
protected IDictionary<string, PermissionDefinition> PermissionDefinitions => _lazyPermissionDefinitions.Value;
private readonly Lazy<Dictionary<string, PermissionDefinition>> _lazyPermissionDefinitions;
protected IDictionary<string, PermissionDefinition> ResourcePermissionDefinitions => _lazyPermissionGroupDefinitions.Value.Item2;
protected AbpPermissionOptions Options { get; }
private readonly IServiceProvider _serviceProvider;
@ -33,12 +35,12 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore,
isThreadSafe: true
);
_lazyPermissionGroupDefinitions = new Lazy<Dictionary<string, PermissionGroupDefinition>>(
_lazyPermissionGroupDefinitions = new Lazy<(Dictionary<string, PermissionGroupDefinition>, Dictionary<string, PermissionDefinition>)>(
CreatePermissionGroupDefinitions,
isThreadSafe: true
);
}
protected virtual Dictionary<string, PermissionDefinition> CreatePermissionDefinitions()
{
var permissions = new Dictionary<string, PermissionDefinition>();
@ -71,7 +73,7 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore,
}
}
protected virtual Dictionary<string, PermissionGroupDefinition> CreatePermissionGroupDefinitions()
protected virtual (Dictionary<string, PermissionGroupDefinition>, Dictionary<string, PermissionDefinition>) CreatePermissionGroupDefinitions()
{
using (var scope = _serviceProvider.CreateScope())
{
@ -99,10 +101,10 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore,
context.CurrentProvider = provider;
provider.PostDefine(context);
}
context.CurrentProvider = null;
return context.Groups;
return (context.Groups, context.ResourcePermissions);
}
}
@ -110,7 +112,7 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore,
{
return Task.FromResult(PermissionDefinitions.GetOrDefault(name));
}
public virtual Task<IReadOnlyList<PermissionDefinition>> GetPermissionsAsync()
{
return Task.FromResult<IReadOnlyList<PermissionDefinition>>(
@ -118,10 +120,22 @@ public class StaticPermissionDefinitionStore : IStaticPermissionDefinitionStore,
);
}
public virtual Task<PermissionDefinition?> GetResourcePermissionOrNullAsync(string name)
{
return Task.FromResult(ResourcePermissionDefinitions.GetOrDefault(name));
}
public virtual Task<IReadOnlyList<PermissionDefinition>> GetResourcePermissionsAsync()
{
return Task.FromResult<IReadOnlyList<PermissionDefinition>>(
ResourcePermissionDefinitions.Values.ToImmutableList()
);
}
public Task<IReadOnlyList<PermissionGroupDefinition>> GetGroupsAsync()
{
return Task.FromResult<IReadOnlyList<PermissionGroupDefinition>>(
PermissionGroupDefinitions.Values.ToImmutableList()
);
}
}
}

13
framework/src/Volo.Abp.Ddd.Domain/Microsoft/Extensions/DependencyInjection/EntityResourcePermissionAuthorizationExtensions.cs

@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Authorization.Permissions.Resources;
namespace Microsoft.Extensions.DependencyInjection;
public static class ResourcePermissionExtenstions
{
public static IServiceCollection AddEntityResourcePermissionAuthorization(this IServiceCollection services)
{
services.AddSingleton<IAuthorizationHandler, EntityResourcePermissionRequirementHandler>();
return services;
}
}

30
framework/src/Volo.Abp.Ddd.Domain/Volo/Abp/Authorization/Permissions/Resources/EntityResourcePermissionRequirementHandler.cs

@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Domain.Entities;
namespace Volo.Abp.Authorization.Permissions.Resources;
public class EntityResourcePermissionRequirementHandler : AuthorizationHandler<ResourcePermissionRequirement, IEntity>
{
protected readonly IResourcePermissionChecker PermissionChecker;
protected EntityResourcePermissionRequirementHandler(IResourcePermissionChecker permissionChecker)
{
PermissionChecker = permissionChecker;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ResourcePermissionRequirement requirement, IEntity? resource)
{
if (resource == null)
{
return;
}
var resourceName = resource.GetType().FullName!;
var resourceKey = resource.GetKeys().JoinAsString(",");
if (await PermissionChecker.IsGrantedAsync(context.User, requirement.PermissionName, resourceName, resourceKey))
{
context.Succeed(requirement);
}
}
}
Loading…
Cancel
Save