Browse Source

Check the permission state of each tree level in its own batch

- Keep the posted permission names untrimmed so they still match their definition
pull/26127/head
maliming 1 day ago
parent
commit
d79292baef
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 36
      modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs
  2. 4
      modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs
  3. 24
      modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs
  4. 6
      modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs
  5. 6
      modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs
  6. 16
      modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestGlobalPermissionStateChecker.cs

36
modules/permission-management/src/Volo.Abp.PermissionManagement.Application/Volo/Abp/PermissionManagement/PermissionAppService.cs

@ -78,27 +78,29 @@ public class PermissionAppService : ApplicationService, IPermissionAppService
.Where(x => !x.Providers.Any() || x.Providers.Contains(providerName))
.Where(x => x.MultiTenancySide.HasFlag(multiTenancySide));
var stateCheckPermissions = permissions.Distinct().ToArray();
var stateCheckResult = stateCheckPermissions.Any()
? await SimpleStateCheckerManager.IsEnabledAsync(stateCheckPermissions)
: new SimpleStateCheckerResult<PermissionDefinition>();
var neededCheckPermissions = new List<PermissionDefinition>();
var neededCheckPermissionSet = new HashSet<PermissionDefinition>();
foreach (var permission in stateCheckPermissions)
var candidatePermissions = permissions.Distinct().ToArray();
var childrenByParent = candidatePermissions
.Where(x => x.Parent != null)
.GroupBy(x => x.Parent!)
.ToDictionary(x => x.Key, x => x.ToArray());
/* The state checkers of a permission only run when its parent is enabled,
so each tree level is checked in its own batch. */
var enabledPermissions = new HashSet<PermissionDefinition>();
var currentLevel = candidatePermissions.Where(x => x.Parent == null).ToArray();
while (currentLevel.Any())
{
if (permission.Parent != null && !neededCheckPermissionSet.Contains(permission.Parent))
{
continue;
}
var levelResult = await SimpleStateCheckerManager.IsEnabledAsync(currentLevel);
var enabledLevelPermissions = currentLevel.Where(x => levelResult[x]).ToArray();
enabledPermissions.UnionWith(enabledLevelPermissions);
if (stateCheckResult[permission])
{
neededCheckPermissions.Add(permission);
neededCheckPermissionSet.Add(permission);
}
currentLevel = enabledLevelPermissions
.SelectMany(x => childrenByParent.GetOrDefault(x) ?? Array.Empty<PermissionDefinition>())
.ToArray();
}
var neededCheckPermissions = candidatePermissions.Where(enabledPermissions.Contains).ToList();
if (!neededCheckPermissions.Any())
{
continue;

4
modules/permission-management/src/Volo.Abp.PermissionManagement.Web/Pages/AbpPermissionManagement/PermissionManagementModal.cshtml.cs

@ -158,9 +158,7 @@ public class PermissionManagementModal : AbpPageModel
{
return names.IsNullOrWhiteSpace()
? Array.Empty<string>()
: names.Split(
new[] { '\r', '\n' },
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
: names.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
}
public class PermissionGroupViewModel

24
modules/permission-management/test/Volo.Abp.PermissionManagement.Application.Tests/Volo/Abp/PermissionManagement/PermissionAppService_Tests.cs

@ -17,6 +17,7 @@ public class PermissionAppService_Tests : AbpPermissionManagementApplicationTest
private readonly IPermissionGrantRepository _permissionGrantRepository;
private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;
private readonly FakePermissionChecker _fakePermissionChecker;
private readonly TestGlobalPermissionStateCheckerCounter _stateCheckerCounter;
public PermissionAppService_Tests()
{
@ -24,6 +25,29 @@ public class PermissionAppService_Tests : AbpPermissionManagementApplicationTest
_permissionGrantRepository = GetRequiredService<IPermissionGrantRepository>();
_currentPrincipalAccessor = GetRequiredService<ICurrentPrincipalAccessor>();
_fakePermissionChecker = GetRequiredService<FakePermissionChecker>();
_stateCheckerCounter = GetRequiredService<TestGlobalPermissionStateCheckerCounter>();
}
[Fact]
public async Task Get_Should_Not_Check_The_State_Of_A_Permission_Whose_Parent_Is_Not_Enabled()
{
_stateCheckerCounter.Reset();
await _permissionAppService.GetAsync(UserPermissionValueProvider.ProviderName,
PermissionTestDataBuilder.User1Id.ToString());
_stateCheckerCounter.CheckedPermissionNames.ShouldContain("MyPermission5");
_stateCheckerCounter.CheckedPermissionNames.ShouldNotContain("MyPermission5.ChildPermission1");
using (_currentPrincipalAccessor.Change(new Claim(AbpClaimTypes.Role, "super-admin")))
{
_stateCheckerCounter.Reset();
await _permissionAppService.GetAsync(UserPermissionValueProvider.ProviderName,
PermissionTestDataBuilder.User1Id.ToString());
_stateCheckerCounter.CheckedPermissionNames.ShouldContain("MyPermission5.ChildPermission1");
}
}
[Fact]

6
modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/AbpPermissionManagementTestModule.cs

@ -5,9 +5,7 @@ using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Features;
using Volo.Abp.GlobalFeatures;
using Volo.Abp.Modularity;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SimpleStateChecking;
using Volo.Abp.Uow;
namespace Volo.Abp.PermissionManagement;
@ -24,10 +22,6 @@ public class AbpPermissionManagementTestModule : AbpModule
{
context.Services.AddEntityFrameworkInMemoryDatabase();
Configure<AbpSimpleStateCheckerOptions<PermissionDefinition>>(options =>
{
options.GlobalStateCheckers.Add<TestGlobalPermissionStateChecker>();
});
var databaseName = Guid.NewGuid().ToString();

6
modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs

@ -4,6 +4,7 @@ using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Autofac;
using Volo.Abp.DistributedLocking;
using Volo.Abp.Modularity;
using Volo.Abp.SimpleStateChecking;
using Volo.Abp.Threading;
namespace Volo.Abp.PermissionManagement;
@ -19,6 +20,11 @@ public class AbpPermissionManagementTestBaseModule : AbpModule
{
context.Services.Replace(ServiceDescriptor.Singleton<IAbpDistributedLock, NullAbpDistributedLock>());
context.Services.Configure<AbpSimpleStateCheckerOptions<PermissionDefinition>>(options =>
{
options.GlobalStateCheckers.Add<TestGlobalPermissionStateChecker>();
});
context.Services.Configure<PermissionManagementOptions>(options =>
{
options.ManagementProviders.Add<TestPermissionManagementProvider>();

16
modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/TestGlobalPermissionStateChecker.cs → modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestGlobalPermissionStateChecker.cs

@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Authorization.Permissions;
@ -13,10 +14,13 @@ public class TestGlobalPermissionStateCheckerCounter : ISingletonDependency
public int SingleCheckCount { get; set; }
public HashSet<string> CheckedPermissionNames { get; } = new HashSet<string>();
public void Reset()
{
BatchCheckCount = 0;
SingleCheckCount = 0;
CheckedPermissionNames.Clear();
}
}
@ -24,13 +28,21 @@ public class TestGlobalPermissionStateChecker : ISimpleBatchStateChecker<Permiss
{
public Task<bool> IsEnabledAsync(SimpleStateCheckerContext<PermissionDefinition> context)
{
GetCounter(context.ServiceProvider).SingleCheckCount++;
var counter = GetCounter(context.ServiceProvider);
counter.SingleCheckCount++;
counter.CheckedPermissionNames.Add(context.State.Name);
return Task.FromResult(true);
}
public Task<SimpleStateCheckerResult<PermissionDefinition>> IsEnabledAsync(SimpleBatchStateCheckerContext<PermissionDefinition> context)
{
GetCounter(context.ServiceProvider).BatchCheckCount++;
var counter = GetCounter(context.ServiceProvider);
counter.BatchCheckCount++;
foreach (var state in context.States)
{
counter.CheckedPermissionNames.Add(state.Name);
}
return Task.FromResult(new SimpleStateCheckerResult<PermissionDefinition>(context.States));
}
Loading…
Cancel
Save