From 0c65fec5610f6d2694dd0e5b4a95ed956a17b375 Mon Sep 17 00:00:00 2001 From: maliming Date: Mon, 22 Feb 2021 22:13:04 +0800 Subject: [PATCH] Add RequiredPermissionName to ToolbarItem. --- .../Toolbars/ToolbarItem.cs | 8 +- .../Toolbars/ToolbarManager.cs | 31 ++++- .../Abp/Ui/Navigation/ApplicationMenuItem.cs | 2 +- .../Volo/Abp/Ui/Navigation/MenuManager.cs | 32 ++--- .../Shared/Permissions/FakePermissionStore.cs | 28 ++++ .../TestPermissionDefinitionProvider.cs | 16 +++ .../UI/Theme/Shared/Toolbars/Toolbar_Tests.cs | 129 ++++++++++++++++++ 7 files changed, 225 insertions(+), 21 deletions(-) create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs create mode 100644 framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs index 9b6ef4becb..4676202c24 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarItem.cs @@ -14,10 +14,14 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars public int Order { get; set; } - public ToolbarItem([NotNull] Type componentType, int order = 0) + [CanBeNull] + public string RequiredPermissionName { get; set; } + + public ToolbarItem([NotNull] Type componentType, int order = 0, string requiredPermissionName = null) { Order = order; ComponentType = Check.NotNull(componentType, nameof(componentType)); + RequiredPermissionName = requiredPermissionName; } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs index f1ac30779a..1f48b2825b 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/Toolbars/ToolbarManager.cs @@ -1,8 +1,11 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.AspNetCore.Mvc.UI.Theming; +using Volo.Abp.Authorization.Permissions; using Volo.Abp.DependencyInjection; namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars @@ -14,7 +17,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars protected IServiceProvider ServiceProvider { get; } public ToolbarManager( - IOptions options, + IOptions options, IServiceProvider serviceProvider, IThemeManager themeManager) { @@ -35,9 +38,33 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars { await contributor.ConfigureToolbarAsync(context); } + + await CheckPermissionsAsync(scope.ServiceProvider, toolbar); } return toolbar; } + + protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, Toolbar toolbar) + { + var requiredPermissionItems = toolbar.Items.Where(x => !x.RequiredPermissionName.IsNullOrWhiteSpace()).ToList(); + + if (requiredPermissionItems.Any()) + { + var permissionChecker = serviceProvider.GetRequiredService(); + var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).ToArray()); + + var toBeDeleted = new List(); + foreach (var item in requiredPermissionItems) + { + if (grantResult.Result[item.RequiredPermissionName!] != PermissionGrantResult.Granted) + { + toBeDeleted.Add(item); + } + } + + toolbar.Items.RemoveAll(toBeDeleted.Contains); + } + } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs index c1e4896513..63f4d7239d 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs @@ -72,7 +72,7 @@ namespace Volo.Abp.UI.Navigation public ApplicationMenuItemList Items { get; } [CanBeNull] - public string RequiredPermissionName { get; } + public string RequiredPermissionName { get; set; } /// /// Can be used to store a custom object related to this menu item. Optional. diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index 6fe6102622..d1f3ee330a 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -45,37 +45,37 @@ namespace Volo.Abp.UI.Navigation protected virtual async Task CheckPermissionsAsync(IServiceProvider serviceProvider, IHasMenuItems menuWithItems) { - var requiredPermissionMenus = new List(); - GetRequiredPermissionNameMenus(menuWithItems, requiredPermissionMenus); + var requiredPermissionItems = new List(); + GetRequiredPermissionNameMenus(menuWithItems, requiredPermissionItems); - if (requiredPermissionMenus.Any()) + if (requiredPermissionItems.Any()) { var permissionChecker = serviceProvider.GetRequiredService(); - var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionMenus.Select(x => x.RequiredPermissionName).ToArray()); + var grantResult = await permissionChecker.IsGrantedAsync(requiredPermissionItems.Select(x => x.RequiredPermissionName).ToArray()); - var toBeDeletedMenus = new List(); - foreach (var menu in requiredPermissionMenus) + var toBeDeleted = new List(); + foreach (var menu in requiredPermissionItems) { if (grantResult.Result[menu.RequiredPermissionName!] != PermissionGrantResult.Granted) { - toBeDeletedMenus.Add(menu); + toBeDeleted.Add(menu); } } - RemoveMenus(menuWithItems, toBeDeletedMenus); + RemoveMenus(menuWithItems, toBeDeleted); } } protected virtual void GetRequiredPermissionNameMenus(IHasMenuItems menuWithItems, List output) { - foreach (var menuItem in menuWithItems.Items) + foreach (var item in menuWithItems.Items) { - if (!menuItem.RequiredPermissionName.IsNullOrWhiteSpace()) + if (!item.RequiredPermissionName.IsNullOrWhiteSpace()) { - output.Add(menuItem); + output.Add(item); } - GetRequiredPermissionNameMenus(menuItem, output); + GetRequiredPermissionNameMenus(item, output); } } @@ -83,17 +83,17 @@ namespace Volo.Abp.UI.Navigation { menuWithItems.Items.RemoveAll(toBeDeleted.Contains); - foreach (var menuItem in menuWithItems.Items) + foreach (var item in menuWithItems.Items) { - RemoveMenus(menuItem, toBeDeleted); + RemoveMenus(item, toBeDeleted); } } protected virtual void NormalizeMenu(IHasMenuItems menuWithItems) { - foreach (var menuItem in menuWithItems.Items) + foreach (var item in menuWithItems.Items) { - NormalizeMenu(menuItem); + NormalizeMenu(item); } menuWithItems.Items.Normalize(); diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs new file mode 100644 index 0000000000..f8f9d21b27 --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/FakePermissionStore.cs @@ -0,0 +1,28 @@ +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Permissions +{ + public class FakePermissionStore : IPermissionStore, ITransientDependency + { + public Task IsGrantedAsync(string name, string providerName, string providerKey) + { + var result = (name.Contains("MyComponent1") || name.Contains("MyComponent3")); + 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.Contains("MyComponent1") || name.Contains("MyComponent3")) + ? PermissionGrantResult.Granted + : PermissionGrantResult.Prohibited); + } + + return Task.FromResult(result); + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs new file mode 100644 index 0000000000..ef706a6c0a --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Permissions/TestPermissionDefinitionProvider.cs @@ -0,0 +1,16 @@ +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Permissions +{ + public class TestPermissionDefinitionProvider : PermissionDefinitionProvider + { + public override void Define(IPermissionDefinitionContext context) + { + var group = context.AddGroup("TestGroup"); + + group.AddPermission("MyComponent1"); + group.AddPermission("MyComponent2"); + group.AddPermission("MyComponent3"); + } + } +} diff --git a/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs new file mode 100644 index 0000000000..70ca907fac --- /dev/null +++ b/framework/test/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests/Volo/Abp/AspNetCore/Mvc/UI/Theme/Shared/Toolbars/Toolbar_Tests.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using NSubstitute; +using Shouldly; +using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars; +using Volo.Abp.AspNetCore.Mvc.UI.Theming; +using Volo.Abp.Security.Claims; +using Xunit; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Tests.Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Toolbars +{ + public class Toolbar_Tests : AbpAspNetCoreMvcUiThemeSharedTestBase + { + protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) + { + services.Configure(options => + { + options.Contributors.Add(new MyToolbarContributor()); + options.Contributors.Add(new MyToolbarContributor2()); + }); + + var claims = new List() { + new Claim(AbpClaimTypes.UserId, "1fcf46b2-28c3-48d0-8bac-fa53268a2775"), + }; + + var identity = new ClaimsIdentity(claims); + var claimsPrincipal = new ClaimsPrincipal(identity); + var principalAccessor = Substitute.For(); + principalAccessor.Principal.Returns(ci => claimsPrincipal); + Thread.CurrentPrincipal = claimsPrincipal; + + var themeManager = Substitute.For(); + themeManager.CurrentTheme.Returns(x => null); + services.Replace(ServiceDescriptor.Singleton(themeManager)); + } + + [Fact] + public void AbpToolbarOptions_Should_Contain_Contributors() + { + var options = GetRequiredService>().Value; + options.Contributors.Count.ShouldBe(2); + options.Contributors.ShouldContain(x => x.GetType() == typeof(MyToolbarContributor)); + options.Contributors.ShouldContain(x => x.GetType() == typeof(MyToolbarContributor2)); + } + + [Fact] + public async Task ToolbarManager_Should_Return_Toolbar() + { + var toolbarManager = GetRequiredService(); + var toolbar = await toolbarManager.GetAsync(StandardToolbars.Main); + + toolbar.Items.Count.ShouldBe(3); + toolbar.Items[0].ComponentType.ShouldBe(typeof(MyComponent1)); + toolbar.Items[1].ComponentType.ShouldBe(typeof(MyComponent3)); + toolbar.Items[2].ComponentType.ShouldBe(typeof(MyComponent4)); + } + + public class MyToolbarContributor : IToolbarContributor + { + public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) + { + if (context.Toolbar.Name != StandardToolbars.Main) + { + return Task.CompletedTask; + } + + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent1), requiredPermissionName: "MyComponent1")); + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent2), requiredPermissionName: "MyComponent2")); + + return Task.CompletedTask; + } + } + + public class MyToolbarContributor2 : IToolbarContributor + { + public Task ConfigureToolbarAsync(IToolbarConfigurationContext context) + { + if (context.Toolbar.Name != StandardToolbars.Main) + { + return Task.CompletedTask; + } + + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent3), requiredPermissionName: "MyComponent3")); + context.Toolbar.Items.Add(new ToolbarItem(typeof(MyComponent4))); + + return Task.CompletedTask; + } + } + + public class MyComponent1 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent1"); + } + } + + public class MyComponent2 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent2"); + } + } + + public class MyComponent3 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent3"); + } + } + + public class MyComponent4 : AbpViewComponent + { + public IViewComponentResult InvokeAsync() + { + return Content("MyComponent4"); + } + } + } +}