83 changed files with 2654 additions and 0 deletions
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
</Weavers> |
@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
||||
<Import Project="..\..\..\configureawait.props" /> |
||||
<Import Project="..\..\..\common.props" /> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>netstandard2.0</TargetFramework> |
||||
<RootNamespace /> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" Version="$(VoloAbpVersion)" /> |
||||
<PackageReference Include="Volo.Abp.Authorization" Version="$(VoloAbpVersion)" /> |
||||
<PackageReference Include="Volo.Abp.PermissionManagement.Application.Contracts" Version="$(VoloAbpVersion)" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<ProjectReference Include="..\Sanhe.Abp.MenuManagement.Domain.Shared\Sanhe.Abp.MenuManagement.Domain.Shared.csproj" /> |
||||
</ItemGroup> |
||||
|
||||
</Project> |
@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
/// <summary> |
||||
/// 授权策略 |
||||
/// </summary> |
||||
public class AuthPolicyDto |
||||
{ |
||||
/// <summary> |
||||
/// 名称 |
||||
/// </summary> |
||||
public string Name { get; set; } |
||||
/// <summary> |
||||
/// 显示名称 |
||||
/// </summary> |
||||
public string DisplayName { get; set; } |
||||
/// <summary> |
||||
/// 子策略 |
||||
/// </summary> |
||||
public List<AuthPolicyDto> Children { get; set; } = new List<AuthPolicyDto>(); |
||||
} |
||||
} |
@ -0,0 +1,97 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.ComponentModel.DataAnnotations; |
||||
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
/// <summary> |
||||
/// 创建修改菜单 |
||||
/// </summary> |
||||
public class CreateOrUpdateMenuDto : EntityDto, IValidatableObject |
||||
{ |
||||
/// <summary> |
||||
/// 名称 |
||||
/// </summary> |
||||
public string Name { get; set; } |
||||
/// <summary> |
||||
/// 显示名称 |
||||
/// </summary> |
||||
public string DisplayName { get; set; } |
||||
/// <summary> |
||||
/// 组件路径 |
||||
/// </summary> |
||||
public string ComponentPath { get; set; } |
||||
/// <summary> |
||||
/// 路由路径 |
||||
/// </summary> |
||||
public string RouterPath { get; set; } |
||||
/// <summary> |
||||
/// 父Id |
||||
/// </summary> |
||||
public Guid? ParentId { get; set; } |
||||
/// <summary> |
||||
/// 菜单类型 |
||||
/// </summary> |
||||
public MenuEnumType MenuType { get; set; } |
||||
/// <summary> |
||||
/// 图标 |
||||
/// </summary> |
||||
public string Icon { get; set; } |
||||
/// <summary> |
||||
/// 排序 |
||||
/// </summary> |
||||
public string Sort { get; set; } |
||||
/// <summary> |
||||
/// window.open _blank |
||||
/// </summary> |
||||
public string TargetUrl { get; set; } |
||||
/// <summary> |
||||
/// 此菜单关联的权限key |
||||
/// </summary> |
||||
public string PermissionKey { get; set; } |
||||
/// <summary> |
||||
/// 表示多租户应用程序中的所属方 |
||||
/// </summary> |
||||
public MultiTenancySides MultiTenancySide { get; set; } |
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) |
||||
{ |
||||
if (MenuType == MenuEnumType.Menu) |
||||
{ |
||||
if (Name.IsNullOrWhiteSpace()) |
||||
{ |
||||
yield return new ValidationResult("Name 不能为空", new[] { "Name" }); |
||||
} |
||||
|
||||
if (DisplayName.IsNullOrWhiteSpace()) |
||||
{ |
||||
yield return new ValidationResult("DisplayName 不能为空", new[] { "DisplayName" }); |
||||
} |
||||
|
||||
if (RouterPath.IsNullOrWhiteSpace()) |
||||
{ |
||||
yield return new ValidationResult("RouterPath 不能为空", new[] { "RouterPath" }); |
||||
} |
||||
|
||||
if (ComponentPath.IsNullOrWhiteSpace()) |
||||
{ |
||||
yield return new ValidationResult("ComponentPath 不能为空", new[] { "ComponentPath" }); |
||||
} |
||||
} |
||||
else if (MenuType == MenuEnumType.Permission) |
||||
{ |
||||
if (DisplayName.IsNullOrWhiteSpace()) |
||||
{ |
||||
yield return new ValidationResult("DisplayName 不能为空", new[] { "DisplayName" }); |
||||
} |
||||
|
||||
if (!ParentId.HasValue) |
||||
{ |
||||
yield return new ValidationResult("ParentId 不能为空", new[] { "ParentId" }); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,44 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
/// <summary> |
||||
/// 前端菜单 |
||||
/// </summary> |
||||
public class FrontMenu |
||||
{ |
||||
/// <summary> |
||||
/// Id |
||||
/// </summary> |
||||
public Guid Id { get; set; } |
||||
/// <summary> |
||||
/// 名称 |
||||
/// </summary> |
||||
public string Name { get; set; } |
||||
/// <summary> |
||||
/// 组件 |
||||
/// </summary> |
||||
public string Component { get; set; } |
||||
/// <summary> |
||||
/// 路径 |
||||
/// </summary> |
||||
public string Path { get; set; } |
||||
/// <summary> |
||||
/// window.open _blank |
||||
/// </summary> |
||||
public string TargetUrl { get; set; } |
||||
/// <summary> |
||||
/// 此菜单关联的权限key. |
||||
/// </summary> |
||||
public string PermissionKey { get; set; } |
||||
/// <summary> |
||||
/// 菜单标签 |
||||
/// </summary> |
||||
public MenuMeta Meta { get; set; } |
||||
/// <summary> |
||||
/// 子菜单 |
||||
/// </summary> |
||||
public List<FrontMenu> Children { get; set; } = new List<FrontMenu>(); |
||||
} |
||||
} |
@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class GetMenuGrantListResultDto |
||||
{ |
||||
public List<MenuGrantInfoDto> MenuGrants { get; set; } |
||||
public List<MenuDto> Menus { get; set; } |
||||
} |
||||
} |
@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class GetMenuResultDto |
||||
{ |
||||
public List<string> PermissionGrants { get; set; } |
||||
public List<FrontMenu> Menus { get; set; } |
||||
} |
||||
} |
@ -0,0 +1,16 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Application.Services; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public interface IMenuAppService : ICrudAppService<MenuDto, Guid, MenuRequestDto, CreateOrUpdateMenuDto> |
||||
{ |
||||
/// <summary> |
||||
/// 获取授权策略 |
||||
/// </summary> |
||||
/// <returns></returns> |
||||
Task<List<AuthPolicyDto>> GetAuthPolicies(); |
||||
} |
||||
} |
@ -0,0 +1,13 @@
|
||||
using JetBrains.Annotations; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Application.Services; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public interface IMenuGrantAppService : IApplicationService |
||||
{ |
||||
Task<GetMenuResultDto> GetListAsync(); |
||||
Task<GetMenuGrantListResultDto> GetAsync([NotNull] string providerName, [NotNull] string providerKey); |
||||
Task UpdateAsync([NotNull] string providerName, [NotNull] string providerKey, UpdateMenuGrantsDto input); |
||||
} |
||||
} |
@ -0,0 +1,63 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuDto : AuditedEntityDto<Guid> |
||||
{ |
||||
/// <summary> |
||||
/// 名称 |
||||
/// </summary> |
||||
public string Name { get; set; } |
||||
/// <summary> |
||||
/// 显示名称 |
||||
/// </summary> |
||||
public string DisplayName { get; set; } |
||||
/// <summary> |
||||
/// 菜单类型 |
||||
/// </summary> |
||||
public MenuEnumType MenuType { get; set; } |
||||
/// <summary> |
||||
/// 组件路径 |
||||
/// </summary> |
||||
public string ComponentPath { get; set; } |
||||
/// <summary> |
||||
/// 路由路径 |
||||
/// </summary> |
||||
public string RouterPath { get; set; } |
||||
/// <summary> |
||||
/// 父级显示名称 |
||||
/// </summary> |
||||
public string ParentDisplayName { get; set; } |
||||
/// <summary> |
||||
/// 父Id |
||||
/// </summary> |
||||
public Guid? ParentId { get; set; } |
||||
/// <summary> |
||||
/// 图标 |
||||
/// </summary> |
||||
public string Icon { get; set; } |
||||
/// <summary> |
||||
/// 排序 |
||||
/// </summary> |
||||
public string Sort { get; set; } |
||||
/// <summary> |
||||
/// window.open _blank |
||||
/// </summary> |
||||
public string TargetUrl { get; set; } |
||||
/// <summary> |
||||
/// 此菜单关联的权限key |
||||
/// </summary> |
||||
public string PermissionKey { get; set; } |
||||
/// <summary> |
||||
/// 表示多租户应用程序中的所属方 |
||||
/// </summary> |
||||
public MultiTenancySides MultiTenancySide { get; set; } |
||||
/// <summary> |
||||
/// 子菜单 |
||||
/// </summary> |
||||
public List<MenuDto> Children { get; set; } = new List<MenuDto>(); |
||||
} |
||||
} |
@ -0,0 +1,17 @@
|
||||
using Volo.Abp.Application; |
||||
using Volo.Abp.Authorization; |
||||
using Volo.Abp.Modularity; |
||||
using Volo.Abp.PermissionManagement; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
[DependsOn( |
||||
typeof(AbpPermissionManagementApplicationContractsModule), |
||||
typeof(MenuManagementDomainSharedModule), |
||||
typeof(AbpDddApplicationContractsModule), |
||||
typeof(AbpAuthorizationModule) |
||||
)] |
||||
public class MenuManagementApplicationContractsModule : AbpModule |
||||
{ |
||||
|
||||
} |
@ -0,0 +1,8 @@
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
public class MenuManagementRemoteServiceConsts |
||||
{ |
||||
public const string RemoteServiceName = "MenuManagement"; |
||||
|
||||
public const string ModuleName = "menuManagement"; |
||||
} |
@ -0,0 +1,14 @@
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuMeta |
||||
{ |
||||
/// <summary> |
||||
/// 标题 |
||||
/// </summary> |
||||
public string Title { get; set; } |
||||
/// <summary> |
||||
/// 图标 |
||||
/// </summary> |
||||
public string Icon { get; set; } |
||||
} |
||||
} |
@ -0,0 +1,14 @@
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuRequestDto |
||||
{ |
||||
/// <summary> |
||||
/// 名称 |
||||
/// </summary> |
||||
public string Name { get; set; } |
||||
/// <summary> |
||||
/// 类型 |
||||
/// </summary> |
||||
public MenuEnumType? Type { get; set; } |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
using Sanhe.Abp.MenuManagement.Localization; |
||||
using Volo.Abp.Authorization.Permissions; |
||||
using Volo.Abp.Localization; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.Permissions; |
||||
|
||||
public class MenuManagementPermissionDefinitionProvider : PermissionDefinitionProvider |
||||
{ |
||||
public override void Define(IPermissionDefinitionContext context) |
||||
{ |
||||
var moduleGroup = context.AddGroup(MenuManagementPermissions.GroupName, L("MenuManagement:MenuManagement")); |
||||
var permission = moduleGroup.AddPermission(MenuManagementPermissions.Menus.Default, L("MenuManagement:MenuManagement"), multiTenancySide: MultiTenancySides.Host); |
||||
permission.AddChild(MenuManagementPermissions.Menus.Create, L("MenuManagement:Create"), multiTenancySide: MultiTenancySides.Host); |
||||
permission.AddChild(MenuManagementPermissions.Menus.Update, L("MenuManagement:Update"), multiTenancySide: MultiTenancySides.Host); |
||||
permission.AddChild(MenuManagementPermissions.Menus.Delete, L("MenuManagement:Delete"), multiTenancySide: MultiTenancySides.Host); |
||||
permission.AddChild(MenuManagementPermissions.Menus.CreatePermission, L("MenuManagement:CreatePermission"), multiTenancySide: MultiTenancySides.Host); |
||||
} |
||||
|
||||
private static LocalizableString L(string name) |
||||
{ |
||||
return LocalizableString.Create<MenuManagementResource>(name); |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
using Volo.Abp.Reflection; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.Permissions; |
||||
|
||||
public class MenuManagementPermissions |
||||
{ |
||||
public const string GroupName = "MenuManagement"; |
||||
|
||||
public static class Menus |
||||
{ |
||||
public const string Default = GroupName + ".Menus"; |
||||
public const string Create = Default + ".Create"; |
||||
public const string Update = Default + ".Update"; |
||||
public const string Delete = Default + ".Delete"; |
||||
public const string CreatePermission = Default + ".CreatePermission"; |
||||
} |
||||
|
||||
public static string[] GetAll() |
||||
{ |
||||
return ReflectionHelper.GetPublicConstantsRecursively(typeof(MenuManagementPermissions)); |
||||
} |
||||
} |
@ -0,0 +1,20 @@
|
||||
using System; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class UpdateMenuGrantDto |
||||
{ |
||||
/// <summary> |
||||
/// 菜单Id |
||||
/// </summary> |
||||
public Guid Id { get; set; } |
||||
/// <summary> |
||||
/// 权限key |
||||
/// </summary> |
||||
public string PermissionKey { get; set; } |
||||
/// <summary> |
||||
/// 是否分配 |
||||
/// </summary> |
||||
public bool IsGranted { get; set; } |
||||
} |
||||
} |
@ -0,0 +1,7 @@
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class UpdateMenuGrantsDto |
||||
{ |
||||
public UpdateMenuGrantDto[] Menus { get; set; } |
||||
} |
||||
} |
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
</Weavers> |
@ -0,0 +1,22 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
||||
<Import Project="..\..\..\configureawait.props" /> |
||||
<Import Project="..\..\..\common.props" /> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>netstandard2.0</TargetFramework> |
||||
<RootNamespace /> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Volo.Abp.AutoMapper" Version="$(VoloAbpVersion)" /> |
||||
<PackageReference Include="Volo.Abp.Ddd.Application" Version="$(VoloAbpVersion)" /> |
||||
<PackageReference Include="Volo.Abp.PermissionManagement.Application" Version="$(VoloAbpVersion)" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<ProjectReference Include="..\Sanhe.Abp.MenuManagement.Application.Contracts\Sanhe.Abp.MenuManagement.Application.Contracts.csproj" /> |
||||
<ProjectReference Include="..\Sanhe.Abp.MenuManagement.Domain\Sanhe.Abp.MenuManagement.Domain.csproj" /> |
||||
</ItemGroup> |
||||
|
||||
</Project> |
@ -0,0 +1,182 @@
|
||||
using Microsoft.AspNetCore.Authorization; |
||||
using Microsoft.Extensions.Localization; |
||||
using Sanhe.Abp.MenuManagement.Permissions; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp; |
||||
using Volo.Abp.Application.Dtos; |
||||
using Volo.Abp.Application.Services; |
||||
using Volo.Abp.Authorization.Permissions; |
||||
using Volo.Abp.Domain.Repositories; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
[Authorize] |
||||
public class MenuAppService : CrudAppService<Menu, MenuDto, Guid, MenuRequestDto, CreateOrUpdateMenuDto, CreateOrUpdateMenuDto>, |
||||
IMenuAppService |
||||
{ |
||||
private readonly IPermissionDefinitionManager _permissionDefinitionManager; |
||||
private readonly IMenuManager _menuManager; |
||||
private readonly IStringLocalizerFactory _stringLocalizerFactory; |
||||
|
||||
public MenuAppService( |
||||
IRepository<Menu, Guid> repository, |
||||
IPermissionDefinitionManager permissionDefinitionManager, |
||||
IMenuManager menuManager, |
||||
IStringLocalizerFactory stringLocalizerFactory |
||||
) : base(repository) |
||||
{ |
||||
_permissionDefinitionManager = permissionDefinitionManager; |
||||
_menuManager = menuManager; |
||||
_stringLocalizerFactory = stringLocalizerFactory; |
||||
} |
||||
|
||||
protected override string GetListPolicyName => MenuManagementPermissions.Menus.Default; |
||||
protected override string CreatePolicyName => MenuManagementPermissions.Menus.Create; |
||||
protected override string UpdatePolicyName => MenuManagementPermissions.Menus.Update; |
||||
protected override string DeletePolicyName => MenuManagementPermissions.Menus.Delete; |
||||
|
||||
public override async Task<MenuDto> UpdateAsync(Guid id, CreateOrUpdateMenuDto input) |
||||
{ |
||||
await PermissionChecker(input.PermissionKey, id); |
||||
|
||||
// 当更新菜单权限时,同时刷 PermissionGrant |
||||
var menu = await GetEntityByIdAsync(id); |
||||
if (menu.PermissionKey != input.PermissionKey) |
||||
{ |
||||
await _menuManager.UpdatePermissionGrantAsync(id, menu.PermissionKey, input.PermissionKey); |
||||
} |
||||
|
||||
return await base.UpdateAsync(id, input); |
||||
} |
||||
|
||||
public virtual Task<List<AuthPolicyDto>> GetAuthPolicies() |
||||
{ |
||||
var result = new List<AuthPolicyDto>(); |
||||
var groups = _permissionDefinitionManager.GetGroups(); |
||||
var multiTenancySide = CurrentTenant.GetMultiTenancySide(); |
||||
foreach (var group in groups) |
||||
{ |
||||
if (group.Permissions.Count == 0) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
foreach (var permission in group.Permissions) |
||||
{ |
||||
if (multiTenancySide != MultiTenancySides.Host && |
||||
!permission.MultiTenancySide.HasFlag(multiTenancySide)) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
var policy = new AuthPolicyDto() |
||||
{ |
||||
Name = permission.Name, |
||||
DisplayName = permission.DisplayName.Localize(_stringLocalizerFactory), |
||||
Children = new List<AuthPolicyDto> |
||||
{ |
||||
new AuthPolicyDto |
||||
{ |
||||
Name = permission.Name, |
||||
DisplayName = permission.DisplayName.Localize(_stringLocalizerFactory) |
||||
} |
||||
} |
||||
}; |
||||
result.Add(policy); |
||||
|
||||
foreach (var c in permission.Children) |
||||
{ |
||||
if (multiTenancySide != MultiTenancySides.Host && |
||||
!c.MultiTenancySide.HasFlag(multiTenancySide)) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
policy.Children.Add(new AuthPolicyDto |
||||
{ |
||||
Name = c.Name, |
||||
DisplayName = c.DisplayName.Localize(_stringLocalizerFactory) |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return Task.FromResult(result); |
||||
} |
||||
|
||||
public override async Task<MenuDto> CreateAsync(CreateOrUpdateMenuDto input) |
||||
{ |
||||
await PermissionChecker(input.PermissionKey); |
||||
return await base.CreateAsync(input); |
||||
} |
||||
|
||||
public override async Task<PagedResultDto<MenuDto>> GetListAsync(MenuRequestDto input) |
||||
{ |
||||
//await CheckGetListPolicyAsync(); |
||||
var queryable = await Repository.GetQueryableAsync(); |
||||
var allMenus = queryable |
||||
.WhereIf(input.Type.HasValue, m => m.MenuType == input.Type) |
||||
.WhereIf(!input.Name.IsNullOrWhiteSpace(), m => m.DisplayName.Contains(input.Name)) |
||||
.ToList(); |
||||
|
||||
var root = allMenus |
||||
.Where(x => !x.ParentId.HasValue) // 没有parentId |
||||
.Union( |
||||
// 有parentId,但是“allMenus"中不存在他的Parent。 |
||||
allMenus.Where(x => x.ParentId.HasValue).Where(x => allMenus.All(y => x.ParentId != y.Id)) |
||||
) |
||||
.OrderBy(x => x.Sort); |
||||
|
||||
var menuDtos = new List<MenuDto>(); |
||||
foreach (var menu in root) |
||||
{ |
||||
var dto = ObjectMapper.Map<Menu, MenuDto>(menu); |
||||
menuDtos.Add(dto); |
||||
// AddChildrenMenuRecursively(dto, allMenus); |
||||
|
||||
SortChildrenMenu(dto); |
||||
} |
||||
|
||||
return new PagedResultDto<MenuDto>(allMenus.Count, menuDtos); |
||||
} |
||||
|
||||
private async Task PermissionChecker(string permissionName, Guid? menuId = null) |
||||
{ |
||||
if (!permissionName.IsNullOrWhiteSpace()) |
||||
{ |
||||
var permission = _permissionDefinitionManager.GetOrNull(permissionName); |
||||
if (permission == null) |
||||
{ |
||||
throw new UserFriendlyException($"未知的权限:“{permissionName}”。"); |
||||
} |
||||
|
||||
var menu = await Repository.FirstOrDefaultAsync(x => x.PermissionKey == permissionName && x.Id != menuId); |
||||
if (menu != null) |
||||
{ |
||||
throw new UserFriendlyException($"权限已经被菜单“{menu.DisplayName}”绑定。"); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void SortChildrenMenu(MenuDto dto) |
||||
{ |
||||
dto.Children.Sort((a, b) => string.Compare(a.Sort, b.Sort, StringComparison.Ordinal)); |
||||
dto.Children.ForEach(SortChildrenMenu); |
||||
} |
||||
|
||||
private void AddChildrenMenuRecursively(MenuDto parent, List<Menu> allMenus) |
||||
{ |
||||
foreach (var menu in allMenus.Where(x => x.ParentId == parent.Id).OrderBy(x => x.Sort)) |
||||
{ |
||||
var dto = ObjectMapper.Map<Menu, MenuDto>(menu); |
||||
parent.Children.Add(dto); |
||||
|
||||
AddChildrenMenuRecursively(dto, allMenus); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,215 @@
|
||||
using Microsoft.AspNetCore.Authorization; |
||||
using Microsoft.Extensions.Options; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp; |
||||
using Volo.Abp.Application.Services; |
||||
using Volo.Abp.Authorization; |
||||
using Volo.Abp.MultiTenancy; |
||||
using Volo.Abp.PermissionManagement; |
||||
using Volo.Abp.Security.Claims; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
[Authorize] |
||||
public class MenuGrantAppService : ApplicationService, IMenuGrantAppService |
||||
{ |
||||
private readonly IAbpAuthorizationPolicyProvider _abpAuthorizationPolicyProvider; |
||||
private readonly IUserMenuGrantChecker _userMenuGrantChecker; |
||||
private readonly ICurrentPrincipalAccessor _principalAccessor; |
||||
private readonly IAuthorizationService _authorizationService; |
||||
private readonly IMenuManager _menuManager; |
||||
private readonly IMenuAppService _menuAppService; |
||||
private readonly IMenuRepository _menuRepository; |
||||
private readonly PermissionManagementOptions _options; |
||||
private readonly IPermissionAppService _permissionAppService; |
||||
|
||||
public MenuGrantAppService( |
||||
IMenuRepository menuRepository, |
||||
IMenuManager menuManager, |
||||
IMenuAppService menuAppService, |
||||
IPermissionAppService permissionAppService, |
||||
IOptions<PermissionManagementOptions> options, |
||||
IAuthorizationService authorizationService, |
||||
IAbpAuthorizationPolicyProvider abpAuthorizationPolicyProvider, |
||||
IUserMenuGrantChecker userMenuGrantChecker, |
||||
ICurrentPrincipalAccessor principalAccessor |
||||
) |
||||
{ |
||||
_menuRepository = menuRepository; |
||||
_menuManager = menuManager; |
||||
_menuAppService = menuAppService; |
||||
_permissionAppService = permissionAppService; |
||||
_authorizationService = authorizationService; |
||||
_abpAuthorizationPolicyProvider = abpAuthorizationPolicyProvider; |
||||
_userMenuGrantChecker = userMenuGrantChecker; |
||||
_principalAccessor = principalAccessor; |
||||
_options = options.Value; |
||||
} |
||||
|
||||
public virtual async Task<GetMenuResultDto> GetListAsync() |
||||
{ |
||||
var queryable = await _menuRepository.GetQueryableAsync(); |
||||
var rootMenus = queryable.Where( |
||||
x => x.MenuType == MenuEnumType.Menu |
||||
) |
||||
.OrderBy(x => x.Sort) |
||||
.ToList() |
||||
.Where(x => !x.ParentId.HasValue).ToList(); // 根节点 |
||||
|
||||
var menuDtos = new List<FrontMenu>(); |
||||
foreach (var menu in rootMenus) |
||||
{ |
||||
var isGranted = await _userMenuGrantChecker.CheckAsync(_principalAccessor.Principal, menu); |
||||
if (isGranted) |
||||
{ |
||||
var dto = ObjectMapper.Map<Menu, FrontMenu>(menu); |
||||
menuDtos.Add(dto); |
||||
await FilterChildrenMenuRecursivelyAsync(menu, dto); |
||||
} |
||||
} |
||||
|
||||
var permissionGrants = new List<string>(); |
||||
var policyNames = await _abpAuthorizationPolicyProvider.GetPoliciesNamesAsync(); |
||||
foreach (var policyName in policyNames) |
||||
{ |
||||
if (await _authorizationService.IsGrantedAsync(policyName)) |
||||
{ |
||||
permissionGrants.Add(policyName); |
||||
} |
||||
} |
||||
|
||||
return new GetMenuResultDto |
||||
{ |
||||
Menus = menuDtos, |
||||
PermissionGrants = permissionGrants |
||||
}; |
||||
} |
||||
|
||||
public virtual async Task<GetMenuGrantListResultDto> GetAsync(string providerName, string providerKey) |
||||
{ |
||||
await CheckProviderPolicy(providerName); |
||||
return await InternalGetAsync(providerName, providerKey); |
||||
} |
||||
|
||||
public virtual async Task UpdateAsync(string providerName, string providerKey, UpdateMenuGrantsDto input) |
||||
{ |
||||
await CheckProviderPolicy(providerName); |
||||
|
||||
foreach (var grantDto in input.Menus) |
||||
{ |
||||
await _menuManager.SetAsync(grantDto.Id, providerName, providerKey, grantDto.IsGranted); |
||||
} |
||||
|
||||
var permissions = _menuManager.GetPermissions(providerName); |
||||
var updatePermissionDtos = permissions |
||||
.Select(x => |
||||
{ |
||||
var menuDto = input.Menus.FirstOrDefault(y => y.PermissionKey == x.Name); |
||||
var dto = new UpdatePermissionDto |
||||
{ |
||||
Name = x.Name, |
||||
IsGranted = menuDto?.IsGranted ?? true // 默认给予授权,如果菜单与权限绑定,则以菜单的授权为主。 |
||||
}; |
||||
|
||||
return dto; |
||||
}) |
||||
.ToArray(); |
||||
|
||||
await _permissionAppService.UpdateAsync( |
||||
providerName, |
||||
providerKey, |
||||
new UpdatePermissionsDto |
||||
{ |
||||
Permissions = updatePermissionDtos |
||||
} |
||||
); |
||||
} |
||||
|
||||
private async Task<GetMenuGrantListResultDto> InternalGetAsync(string providerName, string providerKey) |
||||
{ |
||||
var allMenus = (await _menuRepository.GetQueryableAsync()).ToList(); |
||||
var multiTenancySide = CurrentTenant.GetMultiTenancySide(); |
||||
|
||||
var menuGrants = new List<MenuGrantInfoDto>(); |
||||
|
||||
foreach (var menu in allMenus) |
||||
{ |
||||
if (!menu.MultiTenancySide.HasFlag(multiTenancySide)) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
var grantInfo = await _menuManager.GetAsync(menu.Id, providerName, providerKey); |
||||
menuGrants.Add(new MenuGrantInfoDto |
||||
{ |
||||
Id = menu.Id, |
||||
Name = menu.Name, |
||||
DisplayName = menu.DisplayName, |
||||
PermissionKey = menu.PermissionKey, |
||||
IsGranted = grantInfo.IsGranted, |
||||
GrantedProviders = grantInfo.Providers |
||||
}); |
||||
} |
||||
|
||||
// _menuAppService.GetListAsync 没有做租户过滤,所以 这里要根据当前用户租户过滤。 |
||||
var menuDtos = new List<MenuDto>(); |
||||
foreach (var menu in (await _menuAppService.GetListAsync(new MenuRequestDto())).Items) |
||||
{ |
||||
if (menu.MultiTenancySide.HasFlag(multiTenancySide)) |
||||
{ |
||||
menuDtos.Add(menu); |
||||
FilterChildrenByTenancySide(menu, multiTenancySide); |
||||
} |
||||
} |
||||
|
||||
return new GetMenuGrantListResultDto |
||||
{ |
||||
MenuGrants = menuGrants, |
||||
Menus = menuDtos |
||||
}; |
||||
} |
||||
|
||||
private void FilterChildrenByTenancySide(MenuDto menuDto, MultiTenancySides multiTenancySides) |
||||
{ |
||||
if (menuDto.Children?.Count > 0) |
||||
{ |
||||
menuDto.Children = menuDto.Children.Where(x => x.MultiTenancySide.HasFlag(multiTenancySides)).ToList(); |
||||
foreach (var child in menuDto.Children) |
||||
{ |
||||
FilterChildrenByTenancySide(child, multiTenancySides); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private async Task CheckProviderPolicy(string providerName) |
||||
{ |
||||
var policyName = _options.ProviderPolicies.GetOrDefault(providerName); |
||||
if (policyName.IsNullOrEmpty()) |
||||
{ |
||||
throw new AbpException($"No policy defined to get/set permissions for the provider '{policyName}'. Use {nameof(PermissionManagementOptions)} to map the policy."); |
||||
} |
||||
|
||||
await AuthorizationService.CheckAsync(policyName); |
||||
} |
||||
|
||||
private async Task FilterChildrenMenuRecursivelyAsync(Menu parent, FrontMenu vueMenu) |
||||
{ |
||||
if (parent.Children != null) |
||||
{ |
||||
vueMenu.Children = new List<FrontMenu>(); |
||||
foreach (var menu in parent.Children) |
||||
{ |
||||
if (await _userMenuGrantChecker.CheckAsync(_principalAccessor.Principal, menu)) |
||||
{ |
||||
var dto = ObjectMapper.Map<Menu, FrontMenu>(menu); |
||||
vueMenu.Children.Add(dto); |
||||
await FilterChildrenMenuRecursivelyAsync(menu, dto); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,13 @@
|
||||
using Sanhe.Abp.MenuManagement.Localization; |
||||
using Volo.Abp.Application.Services; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
public abstract class MenuManagementAppService : ApplicationService |
||||
{ |
||||
protected MenuManagementAppService() |
||||
{ |
||||
LocalizationResource = typeof(MenuManagementResource); |
||||
ObjectMapperContext = typeof(MenuManagementApplicationModule); |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
using AutoMapper; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
public class MenuManagementApplicationAutoMapperProfile : Profile |
||||
{ |
||||
public MenuManagementApplicationAutoMapperProfile() |
||||
{ |
||||
CreateMap<Menu, MenuDto>(); |
||||
CreateMap<CreateOrUpdateMenuDto, Menu>(); |
||||
CreateMap<Menu, FrontMenu>() |
||||
.ForMember(d => d.Component, opt => { opt.MapFrom(s => s.ComponentPath); }) |
||||
.ForMember(d => d.Path, opt => { opt.MapFrom(s => s.RouterPath); }) |
||||
.ForMember(d => d.Meta, |
||||
opt => |
||||
{ |
||||
opt.MapFrom(s => new MenuMeta |
||||
{ |
||||
Icon = s.Icon, |
||||
Title = s.DisplayName |
||||
}); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
using Microsoft.Extensions.DependencyInjection; |
||||
using Volo.Abp.Application; |
||||
using Volo.Abp.AutoMapper; |
||||
using Volo.Abp.Modularity; |
||||
using Volo.Abp.PermissionManagement; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
[DependsOn( |
||||
typeof(AbpPermissionManagementApplicationModule), |
||||
typeof(MenuManagementDomainModule), |
||||
typeof(MenuManagementApplicationContractsModule), |
||||
typeof(AbpDddApplicationModule), |
||||
typeof(AbpAutoMapperModule) |
||||
)] |
||||
public class MenuManagementApplicationModule : AbpModule |
||||
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
||||
context.Services.AddAutoMapperObjectMapper<MenuManagementApplicationModule>(); |
||||
Configure<AbpAutoMapperOptions>(options => |
||||
{ |
||||
options.AddMaps<MenuManagementApplicationModule>(); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
<ConfigureAwait /> |
||||
</Weavers> |
@ -0,0 +1,19 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
||||
<Import Project="..\..\..\configureawait.props" /> |
||||
<Import Project="..\..\..\common.props" /> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>netstandard2.0</TargetFramework> |
||||
<RootNamespace /> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Volo.Abp.Identity.Domain" Version="$(VoloAbpVersion)" /> |
||||
<PackageReference Include="Volo.Abp.Identity.Domain.Shared" Version="$(VoloAbpVersion)" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<ProjectReference Include="..\Sanhe.Abp.MenuManagement.Domain\Sanhe.Abp.MenuManagement.Domain.csproj" /> |
||||
</ItemGroup> |
||||
</Project> |
@ -0,0 +1,60 @@
|
||||
using System; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Authorization.Permissions; |
||||
using Volo.Abp.Guids; |
||||
using Volo.Abp.Identity; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.Identity |
||||
{ |
||||
public class RoleMenuManagementProvider : MenuManagementProvider |
||||
{ |
||||
private readonly IUserRoleFinder _userRoleFinder; |
||||
|
||||
public RoleMenuManagementProvider( |
||||
IMenuGrantRepository menuGrantRepository, |
||||
IPermissionDefinitionManager permissionDefinitionManager, |
||||
IMenuGrantChecker menuGrantChecker, |
||||
IGuidGenerator guidGenerator, |
||||
ICurrentTenant currentTenant, |
||||
IUserRoleFinder userRoleFinder) : |
||||
base(menuGrantRepository, |
||||
permissionDefinitionManager, |
||||
menuGrantChecker, |
||||
guidGenerator, |
||||
currentTenant) |
||||
{ |
||||
_userRoleFinder = userRoleFinder; |
||||
} |
||||
|
||||
public override string Name => RolePermissionValueProvider.ProviderName; |
||||
|
||||
public override async Task<MenuGrantInfo> CheckAsync(Guid menuId, string providerName, string providerKey) |
||||
{ |
||||
if (providerName == Name) |
||||
{ |
||||
return new MenuGrantInfo( |
||||
(await MenuGrantChecker.CheckAsync(menuId, providerName, providerKey)).IsGranted, |
||||
providerKey |
||||
); |
||||
} |
||||
|
||||
if (providerName == UserPermissionValueProvider.ProviderName) |
||||
{ |
||||
var userId = Guid.Parse(providerKey); |
||||
var roleNames = await _userRoleFinder.GetRolesAsync(userId); |
||||
|
||||
foreach (var roleName in roleNames) |
||||
{ |
||||
var grantCache = await MenuGrantChecker.CheckAsync(menuId, Name, roleName); |
||||
if (grantCache.IsGranted) |
||||
{ |
||||
return new MenuGrantInfo(true, roleName); |
||||
} |
||||
} |
||||
} |
||||
|
||||
return MenuGrantInfo.NonGranted; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
using Volo.Abp.Authorization.Permissions; |
||||
using Volo.Abp.Guids; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.Identity |
||||
{ |
||||
public class UserMenuManagementProvider : MenuManagementProvider |
||||
{ |
||||
public UserMenuManagementProvider( |
||||
IMenuGrantRepository menuGrantRepository, |
||||
IPermissionDefinitionManager permissionDefinitionManager, |
||||
IMenuGrantChecker menuGrantChecker, |
||||
IGuidGenerator guidGenerator, |
||||
ICurrentTenant currentTenant) : |
||||
base(menuGrantRepository, permissionDefinitionManager, menuGrantChecker, guidGenerator, currentTenant) |
||||
{ |
||||
|
||||
} |
||||
|
||||
public override string Name => UserPermissionValueProvider.ProviderName; |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
using Sanhe.Abp.MenuManagement.Identity; |
||||
using Volo.Abp.Identity; |
||||
using Volo.Abp.Modularity; |
||||
using Volo.Abp.PermissionManagement; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
[DependsOn( |
||||
typeof(AbpIdentityDomainSharedModule), |
||||
typeof(AbpPermissionManagementDomainModule), |
||||
typeof(MenuManagementDomainModule) |
||||
)] |
||||
public class MenuManagementDomainIdentityModule : AbpModule |
||||
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
||||
Configure<MenuManagementOptions>(options => |
||||
{ |
||||
options.ManagementProviders.Add<UserMenuManagementProvider>(); |
||||
options.ManagementProviders.Add<RoleMenuManagementProvider>(); |
||||
}); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
</Weavers> |
@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
||||
<Import Project="..\..\..\configureawait.props" /> |
||||
<Import Project="..\..\..\common.props" /> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>netstandard2.0</TargetFramework> |
||||
<RootNamespace /> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<None Remove="Sanhe\Abp\MenuManagement\Localization\Resources\en.json" /> |
||||
<None Remove="Sanhe\Abp\MenuManagement\Localization\Resources\zh-Hans.json" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<EmbeddedResource Include="Sanhe\Abp\MenuManagement\Localization\Resources\en.json" /> |
||||
<EmbeddedResource Include="Sanhe\Abp\MenuManagement\Localization\Resources\zh-Hans.json" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Volo.Abp.PermissionManagement.Domain.Shared" Version="$(VoloAbpVersion)" /> |
||||
<PackageReference Include="Volo.Abp.Validation" Version="$(VoloAbpVersion)" /> |
||||
</ItemGroup> |
||||
</Project> |
@ -0,0 +1,9 @@
|
||||
using Volo.Abp.Localization; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.Localization; |
||||
|
||||
[LocalizationResourceName("MenuManagement")] |
||||
public class MenuManagementResource |
||||
{ |
||||
|
||||
} |
@ -0,0 +1,25 @@
|
||||
{ |
||||
"culture": "en", |
||||
"texts": { |
||||
"ManageYourProfile": "Manage your profile", |
||||
"Menu:Menu": "MenuMenu", |
||||
"Menu": "Menu", |
||||
"MenuTenantId": "MenuTenantId", |
||||
"MenuName": "MenuName", |
||||
"MenuDisplayName": "MenuDisplayName", |
||||
"MenuMenuType": "MenuMenuType", |
||||
"MenuComponentPath": "MenuComponentPath", |
||||
"MenuRouterPath": "MenuRouterPath", |
||||
"MenuParentId": "MenuParentId", |
||||
"MenuParent": "MenuParent", |
||||
"MenuIcon": "MenuIcon", |
||||
"MenuSort": "MenuSort", |
||||
"MenuTargetUrl": "MenuTargetUrl", |
||||
"MenuPermissionKey": "MenuPermissionKey", |
||||
"MenuChildren": "MenuChildren", |
||||
"CreateMenu": "CreateMenu", |
||||
"EditMenu": "EditMenu", |
||||
"MenuDeletionConfirmationMessage": "Are you sure to delete the menu {0}?", |
||||
"SuccessfullyDeleted": "Successfully deleted" |
||||
} |
||||
} |
@ -0,0 +1,30 @@
|
||||
{ |
||||
"culture": "zh-Hans", |
||||
"texts": { |
||||
"ManageYourProfile": "管理个人资料", |
||||
"Menu:Menu": "MenuMenu", |
||||
"Menu": "Menu", |
||||
"MenuTenantId": "MenuTenantId", |
||||
"MenuName": "MenuName", |
||||
"MenuDisplayName": "MenuDisplayName", |
||||
"MenuMenuType": "MenuMenuType", |
||||
"MenuComponentPath": "MenuComponentPath", |
||||
"MenuRouterPath": "MenuRouterPath", |
||||
"MenuParentId": "MenuParentId", |
||||
"MenuParent": "MenuParent", |
||||
"MenuIcon": "MenuIcon", |
||||
"MenuSort": "MenuSort", |
||||
"MenuTargetUrl": "MenuTargetUrl", |
||||
"MenuPermissionKey": "MenuPermissionKey", |
||||
"MenuChildren": "MenuChildren", |
||||
"CreateMenu": "CreateMenu", |
||||
"EditMenu": "EditMenu", |
||||
"MenuDeletionConfirmationMessage": "Are you sure to delete the menu {0}?", |
||||
"SuccessfullyDeleted": "Successfully deleted", |
||||
"MenuManagement:MenuManagement": "菜单管理", |
||||
"MenuManagement:Create": "创建", |
||||
"MenuManagement:Update": "编辑", |
||||
"MenuManagement:Delete": "删除", |
||||
"MenuManagement:CreatePermission": "创建权限" |
||||
} |
||||
} |
@ -0,0 +1,17 @@
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
/// <summary> |
||||
/// 菜单类型 |
||||
/// </summary> |
||||
public enum MenuEnumType |
||||
{ |
||||
/// <summary> |
||||
/// 菜单 |
||||
/// </summary> |
||||
Menu, |
||||
/// <summary> |
||||
/// 权限 |
||||
/// </summary> |
||||
Permission |
||||
} |
||||
} |
@ -0,0 +1,16 @@
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public static class MenuGrantConsts |
||||
{ |
||||
public const int MaxProviderNameLength = 64; |
||||
|
||||
public const int MaxProviderKeyLength = 64; |
||||
} |
||||
|
||||
public static class MenuConsts |
||||
{ |
||||
public const int MaxProviderNameLength = 64; |
||||
|
||||
public const int MaxProviderKeyLength = 64; |
||||
} |
||||
} |
@ -0,0 +1,18 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuGrantInfoDto |
||||
{ |
||||
/// <summary> |
||||
/// Id |
||||
/// </summary> |
||||
public Guid Id { get; set; } |
||||
public string Name { get; set; } |
||||
public string DisplayName { get; set; } |
||||
public string PermissionKey { get; set; } |
||||
public bool IsGranted { get; set; } |
||||
public List<MenuProviderInfo> GrantedProviders { get; set; } |
||||
} |
||||
} |
@ -0,0 +1,38 @@
|
||||
using Sanhe.Abp.MenuManagement.Localization; |
||||
using Volo.Abp.Localization; |
||||
using Volo.Abp.Localization.ExceptionHandling; |
||||
using Volo.Abp.Modularity; |
||||
using Volo.Abp.PermissionManagement; |
||||
using Volo.Abp.Validation; |
||||
using Volo.Abp.Validation.Localization; |
||||
using Volo.Abp.VirtualFileSystem; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
[DependsOn( |
||||
typeof(AbpValidationModule), |
||||
typeof(AbpPermissionManagementDomainSharedModule) |
||||
)] |
||||
public class MenuManagementDomainSharedModule : AbpModule |
||||
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
||||
Configure<AbpVirtualFileSystemOptions>(options => |
||||
{ |
||||
options.FileSets.AddEmbedded<MenuManagementDomainSharedModule>(); |
||||
}); |
||||
|
||||
Configure<AbpLocalizationOptions>(options => |
||||
{ |
||||
options.Resources |
||||
.Add<MenuManagementResource>("en") |
||||
.AddBaseTypes(typeof(AbpValidationResource)) |
||||
.AddVirtualJson("/Sanhe/Abp/MenuManagement/Localization/Resources"); |
||||
}); |
||||
|
||||
Configure<AbpExceptionLocalizationOptions>(options => |
||||
{ |
||||
options.MapCodeNamespace("MenuManagement", typeof(MenuManagementResource)); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,21 @@
|
||||
using JetBrains.Annotations; |
||||
using Volo.Abp; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuProviderInfo |
||||
{ |
||||
public string Name { get; } |
||||
|
||||
public string Key { get; } |
||||
|
||||
public MenuProviderInfo([NotNull] string name, [NotNull] string key) |
||||
{ |
||||
Check.NotNull(name, nameof(name)); |
||||
Check.NotNull(key, nameof(key)); |
||||
|
||||
Name = name; |
||||
Key = key; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
</Weavers> |
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
||||
<Import Project="..\..\..\configureawait.props" /> |
||||
<Import Project="..\..\..\common.props" /> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>netstandard2.0</TargetFramework> |
||||
<RootNamespace /> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(VoloAbpVersion)" /> |
||||
<PackageReference Include="Volo.Abp.PermissionManagement.Domain" Version="$(VoloAbpVersion)" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<ProjectReference Include="..\Sanhe.Abp.MenuManagement.Domain.Shared\Sanhe.Abp.MenuManagement.Domain.Shared.csproj" /> |
||||
</ItemGroup> |
||||
|
||||
</Project> |
@ -0,0 +1,10 @@
|
||||
using System; |
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public interface IMenuGrantChecker |
||||
{ |
||||
Task<MenuGrantCacheItem> CheckAsync(Guid menuId, string providerName, string providerKey); |
||||
} |
||||
} |
@ -0,0 +1,24 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Domain.Repositories; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public interface IMenuGrantRepository : IBasicRepository<MenuGrant, Guid> |
||||
{ |
||||
Task<MenuGrant> FindAsync(Guid menuId, |
||||
string providerName, |
||||
string providerKey, |
||||
CancellationToken cancellationToken = default); |
||||
|
||||
Task<List<MenuGrant>> GetListAsync( |
||||
string providerName, |
||||
string providerKey, |
||||
CancellationToken cancellationToken = default |
||||
); |
||||
|
||||
Task<List<MenuGrant>> GetGrantByMenuIdAsync(Guid menuId, bool noTracking = true); |
||||
} |
||||
} |
@ -0,0 +1,9 @@
|
||||
using System.Threading.Tasks; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public interface IMenuGrantRuntimeCheckerProvider |
||||
{ |
||||
Task<MenuGrantResultEnum> CheckAsync(MenuGrantRuntimeCheckerContent context); |
||||
} |
||||
} |
@ -0,0 +1,25 @@
|
||||
using JetBrains.Annotations; |
||||
using System; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.DependencyInjection; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public interface IMenuManagementProvider : ITransientDependency |
||||
{ |
||||
string Name { get; } |
||||
|
||||
Task<MenuGrantInfo> CheckAsync( |
||||
[NotNull] Guid menuId, |
||||
[NotNull] string providerName, |
||||
[NotNull] string providerKey |
||||
); |
||||
|
||||
Task SetAsync( |
||||
[NotNull] Guid menuId, |
||||
[NotNull] string providerKey, |
||||
bool isGranted |
||||
); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,15 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Authorization.Permissions; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public interface IMenuManager |
||||
{ |
||||
IReadOnlyList<PermissionDefinition> GetPermissions(string providerName); |
||||
Task<MenuWithGrantedProviders> GetAsync(Guid menuId, string providerName, string providerKey); |
||||
Task SetAsync(Guid menuId, string providerName, string providerKey, bool isGranted); |
||||
Task UpdatePermissionGrantAsync(Guid menuId, string oldPermission, string newPermission); |
||||
} |
||||
} |
@ -0,0 +1,10 @@
|
||||
using System; |
||||
using Volo.Abp.Domain.Repositories; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public interface IMenuRepository : IRepository<Menu, Guid> |
||||
{ |
||||
|
||||
} |
||||
} |
@ -0,0 +1,65 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Security.Claims; |
||||
using System.Security.Principal; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.DependencyInjection; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public interface IUserMenuGrantChecker |
||||
{ |
||||
Task<bool> CheckAsync(ClaimsPrincipal claimsPrincipal, Menu menu); |
||||
} |
||||
|
||||
public class UserMenuGrantChecker : IUserMenuGrantChecker, ITransientDependency |
||||
{ |
||||
private readonly ICurrentTenant _currentTenant; |
||||
private readonly IEnumerable<IMenuGrantRuntimeCheckerProvider> _checkerProviders; |
||||
|
||||
public UserMenuGrantChecker( |
||||
ICurrentTenant currentTenant, |
||||
IEnumerable<IMenuGrantRuntimeCheckerProvider> checkerProviders |
||||
) |
||||
{ |
||||
_currentTenant = currentTenant; |
||||
_checkerProviders = checkerProviders; |
||||
} |
||||
|
||||
public async Task<bool> CheckAsync(ClaimsPrincipal claimsPrincipal, Menu menu) |
||||
{ |
||||
var multiTenancySide = claimsPrincipal?.GetMultiTenancySide() |
||||
?? _currentTenant.GetMultiTenancySide(); |
||||
|
||||
if (!menu.MultiTenancySide.HasFlag(multiTenancySide)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
if (menu.PermissionKey.IsNullOrWhiteSpace()) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
var isGranted = false; |
||||
var content = new MenuGrantRuntimeCheckerContent |
||||
{ |
||||
Menu = menu, |
||||
Principal = claimsPrincipal |
||||
}; |
||||
|
||||
foreach (var provider in _checkerProviders) |
||||
{ |
||||
var result = await provider.CheckAsync(content); |
||||
if (result == MenuGrantResultEnum.Granted) |
||||
{ |
||||
isGranted = true; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return isGranted; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,100 @@
|
||||
using System; |
||||
using System.Collections.ObjectModel; |
||||
using System.ComponentModel; |
||||
using Volo.Abp.Domain.Entities.Auditing; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
/// <summary> |
||||
/// 菜单 |
||||
/// </summary> |
||||
[DisplayName("菜单")] |
||||
public class Menu : FullAuditedAggregateRoot<Guid> |
||||
{ |
||||
/// <summary> |
||||
/// 名称 |
||||
/// </summary> |
||||
[DisplayName("名称")] |
||||
public virtual string Name { get; protected set; } |
||||
/// <summary> |
||||
/// 显示名称 |
||||
/// </summary> |
||||
[DisplayName("显示名称")] |
||||
public virtual string DisplayName { get; protected set; } |
||||
/// <summary> |
||||
/// 类型 |
||||
/// </summary> |
||||
[DisplayName("类型")] |
||||
public virtual MenuEnumType MenuType { get; protected set; } |
||||
/// <summary> |
||||
/// 组件路径 |
||||
/// </summary> |
||||
[DisplayName("组件路径")] |
||||
public virtual string ComponentPath { get; set; } |
||||
/// <summary> |
||||
/// 路由路径 |
||||
/// </summary> |
||||
[DisplayName("路由路径")] |
||||
public virtual string RouterPath { get; set; } |
||||
/// <summary> |
||||
/// 父Id |
||||
/// </summary> |
||||
[DisplayName("父Id")] |
||||
public virtual Guid? ParentId { get; set; } |
||||
/// <summary> |
||||
/// 图标 |
||||
/// </summary> |
||||
[DisplayName("图标")] |
||||
public virtual string Icon { get; set; } |
||||
/// <summary> |
||||
/// 排序 |
||||
/// </summary> |
||||
[DisplayName("排序")] |
||||
public virtual string Sort { get; set; } |
||||
/// <summary> |
||||
/// window.open _blank |
||||
/// </summary> |
||||
[DisplayName("window.open _blank ")] |
||||
public virtual string TargetUrl { get; set; } |
||||
/// <summary> |
||||
/// 此菜单关联的权限key |
||||
/// </summary> |
||||
[DisplayName("此菜单关联的权限key")] |
||||
public virtual string PermissionKey { get; set; } |
||||
/// <summary> |
||||
/// 表示多租户应用程序中的所属方 |
||||
/// </summary> |
||||
[DisplayName("表示多租户应用程序中的所属方")] |
||||
public virtual MultiTenancySides MultiTenancySide { get; set; } |
||||
/// <summary> |
||||
/// 父菜单 |
||||
/// </summary> |
||||
public virtual Menu Parent { get; set; } |
||||
/// <summary> |
||||
/// 子菜单 |
||||
/// </summary> |
||||
public virtual Collection<Menu> Children { get; set; } |
||||
|
||||
protected Menu() |
||||
{ |
||||
} |
||||
|
||||
public Menu( |
||||
Guid id, |
||||
string name, |
||||
string displayName, |
||||
MenuEnumType menuType, |
||||
MultiTenancySides multiTenancySide = MultiTenancySides.Both |
||||
) |
||||
{ |
||||
Id = id; |
||||
Name = name; |
||||
DisplayName = displayName; |
||||
MenuType = menuType; |
||||
MultiTenancySide = multiTenancySide; |
||||
|
||||
Children = new Collection<Menu>(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,60 @@
|
||||
using JetBrains.Annotations; |
||||
using System; |
||||
using System.ComponentModel; |
||||
using Volo.Abp; |
||||
using Volo.Abp.Domain.Entities; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
/// <summary> |
||||
/// 菜单分配 |
||||
/// </summary> |
||||
[DisplayName("菜单分配")] |
||||
public class MenuGrant : Entity<Guid>, IMultiTenant |
||||
{ |
||||
/// <summary> |
||||
/// 租户Id |
||||
/// </summary> |
||||
[DisplayName("租户Id")] |
||||
public virtual Guid? TenantId { get; protected set; } |
||||
/// <summary> |
||||
/// 菜单Id |
||||
/// </summary> |
||||
[DisplayName("菜单Id")] |
||||
[NotNull] |
||||
public virtual Guid MenuId { get; protected set; } |
||||
/// <summary> |
||||
/// 提供器名称 |
||||
/// </summary> |
||||
[DisplayName("提供器名称")] |
||||
[NotNull] |
||||
public virtual string ProviderName { get; protected set; } |
||||
/// <summary> |
||||
/// 提供器Key |
||||
/// </summary> |
||||
[DisplayName("提供器Key")] |
||||
[CanBeNull] |
||||
public virtual string ProviderKey { get; protected internal set; } |
||||
|
||||
protected MenuGrant() |
||||
{ |
||||
} |
||||
|
||||
public MenuGrant( |
||||
Guid id, |
||||
[NotNull] Guid menuId, |
||||
[NotNull] string providerName, |
||||
[CanBeNull] string providerKey, |
||||
Guid? tenantId = null) |
||||
{ |
||||
Check.NotNull(menuId, nameof(menuId)); |
||||
|
||||
Id = id; |
||||
MenuId = menuId; |
||||
ProviderName = Check.NotNullOrWhiteSpace(providerName, nameof(providerName)); |
||||
ProviderKey = providerKey; |
||||
TenantId = tenantId; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,27 @@
|
||||
using System; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
[Serializable] |
||||
public class MenuGrantCacheItem |
||||
{ |
||||
public Guid MenuId { get; set; } |
||||
public bool IsGranted { get; set; } |
||||
|
||||
public MenuGrantCacheItem() |
||||
{ |
||||
|
||||
} |
||||
|
||||
public MenuGrantCacheItem(Guid menuId, bool isGranted) |
||||
{ |
||||
MenuId = menuId; |
||||
IsGranted = isGranted; |
||||
} |
||||
|
||||
public static string CalculateCacheKey(Guid menuId, string providerName, string providerKey) |
||||
{ |
||||
return "pn:" + providerName + ",pk:" + providerKey + ",m:" + menuId; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,65 @@
|
||||
using System; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Caching; |
||||
using Volo.Abp.DependencyInjection; |
||||
using Volo.Abp.Domain.Entities.Events; |
||||
using Volo.Abp.EventBus; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuGrantCacheItemInvalidator : |
||||
ILocalEventHandler<EntityCreatedEventData<MenuGrant>>, |
||||
ILocalEventHandler<EntityDeletedEventData<MenuGrant>>, |
||||
ITransientDependency |
||||
{ |
||||
public MenuGrantCacheItemInvalidator( |
||||
ICurrentTenant currentTenant, |
||||
IDistributedCache<MenuGrantCacheItem> cache |
||||
) |
||||
{ |
||||
CurrentTenant = currentTenant; |
||||
Cache = cache; |
||||
} |
||||
|
||||
protected ICurrentTenant CurrentTenant { get; } |
||||
|
||||
protected IDistributedCache<MenuGrantCacheItem> Cache { get; } |
||||
|
||||
public async Task HandleEventAsync(EntityCreatedEventData<MenuGrant> eventData) |
||||
{ |
||||
var cacheKey = CalculateCacheKey( |
||||
eventData.Entity.MenuId, |
||||
eventData.Entity.ProviderName, |
||||
eventData.Entity.ProviderKey |
||||
); |
||||
|
||||
using (CurrentTenant.Change(eventData.Entity.TenantId)) |
||||
{ |
||||
await Cache.SetAsync(cacheKey, new MenuGrantCacheItem(eventData.Entity.MenuId, true)); |
||||
} |
||||
} |
||||
|
||||
public async Task HandleEventAsync(EntityDeletedEventData<MenuGrant> eventData) |
||||
{ |
||||
var cacheKey = CalculateCacheKey( |
||||
eventData.Entity.MenuId, |
||||
eventData.Entity.ProviderName, |
||||
eventData.Entity.ProviderKey |
||||
); |
||||
|
||||
using (CurrentTenant.Change(eventData.Entity.TenantId)) |
||||
{ |
||||
await Cache.SetAsync(cacheKey, new MenuGrantCacheItem(eventData.Entity.MenuId, false)); |
||||
} |
||||
} |
||||
|
||||
protected virtual string CalculateCacheKey( |
||||
Guid menuId, |
||||
string providerName, |
||||
string providerKey) |
||||
{ |
||||
return MenuGrantCacheItem.CalculateCacheKey(menuId, providerName, providerKey); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,59 @@
|
||||
using Microsoft.Extensions.Logging; |
||||
using System; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Caching; |
||||
using Volo.Abp.DependencyInjection; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuGrantChecker : IMenuGrantChecker, ITransientDependency |
||||
{ |
||||
private readonly IDistributedCache<MenuGrantCacheItem> _cache; |
||||
private readonly ILogger<MenuGrantChecker> _logger; |
||||
private readonly IMenuGrantRepository _menuGrantRepository; |
||||
|
||||
public MenuGrantChecker( |
||||
IDistributedCache<MenuGrantCacheItem> cache, |
||||
ILogger<MenuGrantChecker> logger, |
||||
IMenuGrantRepository menuGrantRepository |
||||
) |
||||
{ |
||||
_cache = cache; |
||||
_logger = logger; |
||||
_menuGrantRepository = menuGrantRepository; |
||||
} |
||||
|
||||
public async Task<MenuGrantCacheItem> CheckAsync(Guid menuId, string providerName, string providerKey) |
||||
{ |
||||
var cacheKey = MenuGrantCacheItem.CalculateCacheKey(menuId, providerName, providerKey); |
||||
|
||||
_logger.LogDebug("MenuGrantCheckerCache.CheckAsync: {cacheKey}", cacheKey); |
||||
|
||||
var cacheItem = await _cache.GetAsync(cacheKey); |
||||
|
||||
if (cacheItem != null) |
||||
{ |
||||
_logger.LogDebug("Found in the cache: {cacheKey}", cacheKey); |
||||
return cacheItem; |
||||
} |
||||
|
||||
_logger.LogDebug("Not found in the cache, getting from the repository: {cacheKey}", cacheKey); |
||||
|
||||
cacheItem = new MenuGrantCacheItem( |
||||
menuId, |
||||
await _menuGrantRepository.FindAsync(menuId, providerName, providerKey) != null |
||||
); |
||||
|
||||
_logger.LogDebug("Setting the cache item: {cacheKey}", cacheKey); |
||||
|
||||
await _cache.SetAsync( |
||||
cacheKey, |
||||
cacheItem |
||||
); |
||||
|
||||
_logger.LogDebug("Finished setting the cache item: {cacheKey}", cacheKey); |
||||
|
||||
return cacheItem; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,19 @@
|
||||
using JetBrains.Annotations; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuGrantInfo |
||||
{ |
||||
public static MenuGrantInfo NonGranted { get; } = new MenuGrantInfo(false); |
||||
|
||||
public virtual bool IsGranted { get; } |
||||
|
||||
public virtual string ProviderKey { get; } |
||||
|
||||
public MenuGrantInfo(bool isGranted, [CanBeNull] string providerKey = null) |
||||
{ |
||||
IsGranted = isGranted; |
||||
ProviderKey = providerKey; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,8 @@
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public enum MenuGrantResultEnum |
||||
{ |
||||
Undefined, |
||||
Granted |
||||
} |
||||
} |
@ -0,0 +1,10 @@
|
||||
using System.Security.Claims; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuGrantRuntimeCheckerContent |
||||
{ |
||||
public Menu Menu { get; set; } |
||||
public ClaimsPrincipal Principal { get; set; } |
||||
} |
||||
} |
@ -0,0 +1,61 @@
|
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.DependencyInjection; |
||||
using Volo.Abp.Security.Claims; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public abstract class MenuGrantRuntimeCheckerProvider : IMenuGrantRuntimeCheckerProvider |
||||
{ |
||||
protected IMenuGrantChecker MenuGrantChecker { get; } |
||||
|
||||
protected MenuGrantRuntimeCheckerProvider(IMenuGrantChecker menuGrantChecker) |
||||
{ |
||||
MenuGrantChecker = menuGrantChecker; |
||||
} |
||||
|
||||
public abstract Task<MenuGrantResultEnum> CheckAsync(MenuGrantRuntimeCheckerContent context); |
||||
} |
||||
|
||||
public class RoleMenuGrantRuntimeCheckerProvider : MenuGrantRuntimeCheckerProvider, ITransientDependency |
||||
{ |
||||
public RoleMenuGrantRuntimeCheckerProvider(IMenuGrantChecker menuGrantChecker) : base(menuGrantChecker) |
||||
{ |
||||
} |
||||
|
||||
public override async Task<MenuGrantResultEnum> CheckAsync(MenuGrantRuntimeCheckerContent context) |
||||
{ |
||||
var roles = context.Principal?.FindAll(AbpClaimTypes.Role).Select(c => c.Value).ToArray(); |
||||
|
||||
if (roles == null || !roles.Any()) |
||||
{ |
||||
return MenuGrantResultEnum.Undefined; |
||||
} |
||||
|
||||
foreach (var role in roles) |
||||
{ |
||||
var result = await MenuGrantChecker.CheckAsync(context.Menu.Id, "R", role); |
||||
if (result.IsGranted) |
||||
{ |
||||
return MenuGrantResultEnum.Granted; |
||||
} |
||||
} |
||||
|
||||
return MenuGrantResultEnum.Undefined; |
||||
} |
||||
} |
||||
|
||||
public class UserMenuGrantRuntimeCheckerProvider : MenuGrantRuntimeCheckerProvider, ITransientDependency |
||||
{ |
||||
public UserMenuGrantRuntimeCheckerProvider(IMenuGrantChecker menuGrantChecker) : base(menuGrantChecker) |
||||
{ |
||||
} |
||||
|
||||
public override async Task<MenuGrantResultEnum> CheckAsync(MenuGrantRuntimeCheckerContent context) |
||||
{ |
||||
var userId = context.Principal?.FindFirst(AbpClaimTypes.UserId)?.Value; |
||||
var result = await MenuGrantChecker.CheckAsync(context.Menu.Id, "U", userId); |
||||
return result.IsGranted ? MenuGrantResultEnum.Granted : MenuGrantResultEnum.Undefined; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,10 @@
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
public static class MenuManagementDbProperties |
||||
{ |
||||
public static string DbTablePrefix { get; set; } = "MenuManagement"; |
||||
|
||||
public static string DbSchema { get; set; } = null; |
||||
|
||||
public const string ConnectionStringName = "MenuManagement"; |
||||
} |
@ -0,0 +1,13 @@
|
||||
using Volo.Abp.Domain; |
||||
using Volo.Abp.Modularity; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
[DependsOn( |
||||
typeof(AbpDddDomainModule), |
||||
typeof(MenuManagementDomainSharedModule) |
||||
)] |
||||
public class MenuManagementDomainModule : AbpModule |
||||
{ |
||||
|
||||
} |
@ -0,0 +1,14 @@
|
||||
using Volo.Abp.Collections; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuManagementOptions |
||||
{ |
||||
public ITypeList<IMenuManagementProvider> ManagementProviders { get; } |
||||
|
||||
public MenuManagementOptions() |
||||
{ |
||||
ManagementProviders = new TypeList<IMenuManagementProvider>(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,81 @@
|
||||
using System; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Authorization.Permissions; |
||||
using Volo.Abp.Guids; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public abstract class MenuManagementProvider : IMenuManagementProvider |
||||
{ |
||||
protected IMenuGrantRepository MenuGrantRepository { get; } |
||||
protected IPermissionDefinitionManager PermissionDefinitionManager { get; } |
||||
protected IMenuGrantChecker MenuGrantChecker { get; } |
||||
protected IGuidGenerator GuidGenerator { get; } |
||||
protected ICurrentTenant CurrentTenant { get; } |
||||
public abstract string Name { get; } |
||||
|
||||
protected MenuManagementProvider(IMenuGrantRepository menuGrantRepository, |
||||
IPermissionDefinitionManager permissionDefinitionManager, |
||||
IMenuGrantChecker menuGrantChecker, |
||||
IGuidGenerator guidGenerator, |
||||
ICurrentTenant currentTenant) |
||||
{ |
||||
MenuGrantRepository = menuGrantRepository; |
||||
PermissionDefinitionManager = permissionDefinitionManager; |
||||
MenuGrantChecker = menuGrantChecker; |
||||
GuidGenerator = guidGenerator; |
||||
CurrentTenant = currentTenant; |
||||
} |
||||
|
||||
public virtual async Task<MenuGrantInfo> CheckAsync(Guid menuId, string providerName, string providerKey) |
||||
{ |
||||
if (providerName != Name) |
||||
{ |
||||
return MenuGrantInfo.NonGranted; |
||||
} |
||||
|
||||
return new MenuGrantInfo( |
||||
(await MenuGrantChecker.CheckAsync(menuId, providerName, providerKey)).IsGranted, |
||||
providerKey |
||||
); |
||||
} |
||||
|
||||
public virtual Task SetAsync(Guid menuId, string providerKey, bool isGranted) |
||||
{ |
||||
return isGranted |
||||
? GrantAsync(menuId, providerKey) |
||||
: RevokeAsync(menuId, providerKey); |
||||
} |
||||
|
||||
protected virtual async Task GrantAsync(Guid menuId, string providerKey) |
||||
{ |
||||
var menuGrant = await MenuGrantRepository.FindAsync(menuId, Name, providerKey); |
||||
if (menuGrant != null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
await MenuGrantRepository.InsertAsync( |
||||
new MenuGrant( |
||||
GuidGenerator.Create(), |
||||
menuId, |
||||
Name, |
||||
providerKey, |
||||
CurrentTenant.Id |
||||
) |
||||
); |
||||
} |
||||
|
||||
protected virtual async Task RevokeAsync(Guid menuId, string providerKey) |
||||
{ |
||||
var permissionGrant = await MenuGrantRepository.FindAsync(menuId, Name, providerKey); |
||||
if (permissionGrant == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
await MenuGrantRepository.DeleteAsync(permissionGrant); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,116 @@
|
||||
using Microsoft.Extensions.DependencyInjection; |
||||
using Microsoft.Extensions.Options; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Collections.Immutable; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp; |
||||
using Volo.Abp.Authorization.Permissions; |
||||
using Volo.Abp.DependencyInjection; |
||||
using Volo.Abp.MultiTenancy; |
||||
using Volo.Abp.PermissionManagement; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuManager : IMenuManager, ITransientDependency |
||||
{ |
||||
private readonly IPermissionDefinitionManager _permissionDefinitionManager; |
||||
private readonly IMenuGrantRepository _menuGrantRepository; |
||||
private readonly IPermissionManager _permissionManager; |
||||
private readonly ICurrentTenant _currentTenant; |
||||
private readonly IReadOnlyList<IMenuManagementProvider> _managementProviders; |
||||
private readonly MenuManagementOptions _options; |
||||
|
||||
public MenuManager( |
||||
IPermissionDefinitionManager permissionDefinitionManager, |
||||
IMenuGrantRepository menuGrantRepository, |
||||
IPermissionManager permissionManager, |
||||
IOptions<MenuManagementOptions> options, |
||||
IServiceProvider serviceProvider, |
||||
ICurrentTenant currentTenant) |
||||
{ |
||||
_permissionDefinitionManager = permissionDefinitionManager; |
||||
_menuGrantRepository = menuGrantRepository; |
||||
_permissionManager = permissionManager; |
||||
_currentTenant = currentTenant; |
||||
_options = options.Value; |
||||
|
||||
_managementProviders = _options.ManagementProviders |
||||
.Select(c => serviceProvider.GetRequiredService(c) as IMenuManagementProvider) |
||||
.ToList(); |
||||
} |
||||
|
||||
public virtual IReadOnlyList<PermissionDefinition> GetPermissions(string providerName) |
||||
{ |
||||
var multiTenancySide = _currentTenant.GetMultiTenancySide(); |
||||
|
||||
var permissions = _permissionDefinitionManager.GetPermissions(); |
||||
return permissions.Where(x => |
||||
{ |
||||
if (x.Providers.Any() && !x.Providers.Contains(providerName)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
if (!x.MultiTenancySide.HasFlag(multiTenancySide)) |
||||
{ |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
}).ToImmutableList(); |
||||
} |
||||
|
||||
public virtual async Task<MenuWithGrantedProviders> GetAsync(Guid menuId, string providerName, string providerKey) |
||||
{ |
||||
var result = new MenuWithGrantedProviders(menuId, false); |
||||
|
||||
foreach (var provider in _managementProviders) |
||||
{ |
||||
var providerResult = await provider.CheckAsync(menuId, providerName, providerKey); |
||||
if (providerResult.IsGranted) |
||||
{ |
||||
result.IsGranted = true; |
||||
result.Providers.Add(new MenuProviderInfo(provider.Name, providerResult.ProviderKey)); |
||||
} |
||||
} |
||||
|
||||
return result; |
||||
} |
||||
|
||||
public virtual async Task SetAsync(Guid menuId, string providerName, string providerKey, bool isGranted) |
||||
{ |
||||
var currentGrantInfo = await GetAsync(menuId, providerName, providerKey); |
||||
if (currentGrantInfo.IsGranted == isGranted) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
var provider = _managementProviders.FirstOrDefault(m => m.Name == providerName); |
||||
if (provider == null) |
||||
{ |
||||
throw new UserFriendlyException("Unknown menu management provider: " + providerName); |
||||
} |
||||
|
||||
await provider.SetAsync(menuId, providerKey, isGranted); |
||||
} |
||||
|
||||
public virtual async Task UpdatePermissionGrantAsync(Guid menuId, string oldPermission, string newPermission) |
||||
{ |
||||
var menuGrants = await _menuGrantRepository.GetGrantByMenuIdAsync(menuId); |
||||
foreach (var g in menuGrants) |
||||
{ |
||||
if (!oldPermission.IsNullOrEmpty() && !newPermission.IsNullOrEmpty()) // 菜单原本有权限控制,修改为无权限控制:这种情况不清除授权,视为开放权限。 |
||||
{ |
||||
await _permissionManager.SetAsync(oldPermission, g.ProviderName, g.ProviderKey, false); |
||||
} |
||||
|
||||
if (!newPermission.IsNullOrEmpty()) |
||||
{ |
||||
await _permissionManager.SetAsync(newPermission, g.ProviderName, g.ProviderKey, true); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
using JetBrains.Annotations; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using Volo.Abp; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuWithGrantedProviders |
||||
{ |
||||
public Guid MenuId { get; } |
||||
|
||||
public bool IsGranted { get; set; } |
||||
|
||||
public List<MenuProviderInfo> Providers { get; set; } |
||||
|
||||
public MenuWithGrantedProviders([NotNull] Guid menuId, bool isGranted) |
||||
{ |
||||
Check.NotNull(menuId, nameof(menuId)); |
||||
|
||||
MenuId = menuId; |
||||
IsGranted = isGranted; |
||||
|
||||
Providers = new List<MenuProviderInfo>(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,48 @@
|
||||
using System; |
||||
using System.Collections.ObjectModel; |
||||
using System.Linq; |
||||
using Volo.Abp.Domain.Entities.Auditing; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class Permission : AuditedEntity<Guid>, IMultiTenant |
||||
{ |
||||
public virtual Guid? TenantId { get; protected set; } |
||||
public virtual string Key { get; protected set; } |
||||
public virtual string Name { get; protected set; } |
||||
public virtual Guid GroupId { get; protected set; } |
||||
public virtual PermissionGroup Group { get; protected set; } |
||||
public virtual Guid? ParentId { get; set; } |
||||
public virtual Permission Parent { get; set; } |
||||
public virtual Collection<Permission> Children { get; set; } |
||||
|
||||
protected Permission() |
||||
{ |
||||
} |
||||
|
||||
public Permission(Guid id, string key, string name, Guid groupId) |
||||
{ |
||||
Id = id; |
||||
Key = key; |
||||
Name = name; |
||||
GroupId = groupId; |
||||
Children = new Collection<Permission>(); |
||||
} |
||||
|
||||
public virtual Permission AddChildren(Guid id, string key, string name) |
||||
{ |
||||
if (Children.Any(x => x.Key == key)) |
||||
{ |
||||
throw new Volo.Abp.UserFriendlyException("权限名重复"); |
||||
} |
||||
|
||||
var page = new Permission(id, key, name, GroupId); |
||||
page.Parent = this; |
||||
page.ParentId = Id; |
||||
Children.Add(page); |
||||
|
||||
return page; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,63 @@
|
||||
using System; |
||||
using System.Collections.ObjectModel; |
||||
using System.Linq; |
||||
using Volo.Abp.Domain.Entities.Auditing; |
||||
using Volo.Abp.MultiTenancy; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class PermissionGroup : AuditedEntity<Guid>, IMultiTenant |
||||
{ |
||||
public virtual Guid? TenantId { get; protected set; } |
||||
public virtual string Key { get; protected set; } |
||||
public virtual string Name { get; protected set; } |
||||
public virtual Guid? ParentId { get; set; } |
||||
public virtual PermissionGroup Parent { get; set; } |
||||
public virtual Collection<PermissionGroup> Children { get; set; } |
||||
public virtual Collection<Permission> Permissions { get; set; } |
||||
|
||||
protected PermissionGroup() |
||||
{ |
||||
} |
||||
|
||||
public PermissionGroup(Guid id, string key, string name, Guid? tenantId) |
||||
{ |
||||
Id = id; |
||||
Key = key; |
||||
Name = name; |
||||
TenantId = tenantId; |
||||
|
||||
Children = new Collection<PermissionGroup>(); |
||||
Permissions = new Collection<Permission>(); |
||||
} |
||||
|
||||
public virtual Permission AddPermission(Guid id, string key, string name) |
||||
{ |
||||
if (Permissions.Any(x => x.Key == key)) |
||||
{ |
||||
throw new Volo.Abp.UserFriendlyException("权限名重复"); |
||||
} |
||||
|
||||
var permission = new Permission(id, key, name, Id); |
||||
|
||||
Permissions.Add(permission); |
||||
|
||||
return permission; |
||||
} |
||||
|
||||
public virtual PermissionGroup AddChildren(Guid id, string key, string name, Guid? tenantId = null) |
||||
{ |
||||
if (Children.Any(x => x.Key == key)) |
||||
{ |
||||
throw new Volo.Abp.UserFriendlyException("分组名重复"); |
||||
} |
||||
|
||||
var group = new PermissionGroup(id, key, name, tenantId); |
||||
group.Parent = this; |
||||
group.ParentId = Id; |
||||
Children.Add(group); |
||||
|
||||
return group; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,13 @@
|
||||
using Volo.Abp.Settings; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.Settings; |
||||
|
||||
public class MenuManagementSettingDefinitionProvider : SettingDefinitionProvider |
||||
{ |
||||
public override void Define(ISettingDefinitionContext context) |
||||
{ |
||||
/* Define module settings here. |
||||
* Use names from MenuManagementSettings class. |
||||
*/ |
||||
} |
||||
} |
@ -0,0 +1,10 @@
|
||||
namespace Sanhe.Abp.MenuManagement.Settings; |
||||
|
||||
public static class MenuManagementSettings |
||||
{ |
||||
public const string GroupName = "MenuManagement"; |
||||
|
||||
/* Add constants for setting names. Example: |
||||
* public const string MySettingName = GroupName + ".MySettingName"; |
||||
*/ |
||||
} |
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
</Weavers> |
@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
||||
<Import Project="..\..\..\configureawait.props" /> |
||||
<Import Project="..\..\..\common.props" /> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>net6.0</TargetFramework> |
||||
<RootNamespace /> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Volo.Abp.EntityFrameworkCore" Version="$(VoloAbpVersion)" /> |
||||
<PackageReference Include="Volo.Abp.PermissionManagement.EntityFrameworkCore" Version="$(VoloAbpVersion)" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<ProjectReference Include="..\Sanhe.Abp.MenuManagement.Domain\Sanhe.Abp.MenuManagement.Domain.csproj" /> |
||||
</ItemGroup> |
||||
|
||||
</Project> |
@ -0,0 +1,12 @@
|
||||
using Microsoft.EntityFrameworkCore; |
||||
using Volo.Abp.Data; |
||||
using Volo.Abp.EntityFrameworkCore; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.EntityFrameworkCore; |
||||
|
||||
[ConnectionStringName(MenuManagementDbProperties.ConnectionStringName)] |
||||
public interface IMenuManagementDbContext : IEfCoreDbContext |
||||
{ |
||||
DbSet<Menu> Menus { get; set; } |
||||
DbSet<MenuGrant> MenuGrants { get; set; } |
||||
} |
@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore; |
||||
using Volo.Abp.Data; |
||||
using Volo.Abp.EntityFrameworkCore; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.EntityFrameworkCore; |
||||
|
||||
[ConnectionStringName(MenuManagementDbProperties.ConnectionStringName)] |
||||
public class MenuManagementDbContext : AbpDbContext<MenuManagementDbContext>, IMenuManagementDbContext |
||||
{ |
||||
public DbSet<Menu> Menus { get; set; } |
||||
public DbSet<MenuGrant> MenuGrants { get; set; } |
||||
|
||||
public MenuManagementDbContext(DbContextOptions<MenuManagementDbContext> options) |
||||
: base(options) |
||||
{ |
||||
|
||||
} |
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder) |
||||
{ |
||||
base.OnModelCreating(builder); |
||||
|
||||
builder.ConfigureMenuManagement(); |
||||
} |
||||
} |
@ -0,0 +1,43 @@
|
||||
using Microsoft.EntityFrameworkCore; |
||||
using Volo.Abp; |
||||
using Volo.Abp.EntityFrameworkCore.Modeling; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.EntityFrameworkCore; |
||||
|
||||
public static class MenuManagementDbContextModelCreatingExtensions |
||||
{ |
||||
public static void ConfigureMenuManagement( |
||||
this ModelBuilder builder) |
||||
{ |
||||
Check.NotNull(builder, nameof(builder)); |
||||
|
||||
builder.Entity<Menu>(b => |
||||
{ |
||||
b.ToTable(MenuManagementDbProperties.DbTablePrefix + "Menus", MenuManagementDbProperties.DbSchema); |
||||
b.ConfigureByConvention(); |
||||
|
||||
b.Property(x => x.Name).HasMaxLength(50); |
||||
b.Property(x => x.DisplayName).HasMaxLength(50); |
||||
b.Property(x => x.ComponentPath).HasMaxLength(100); |
||||
b.Property(x => x.RouterPath).HasMaxLength(100); |
||||
b.Property(x => x.Icon).HasMaxLength(50); |
||||
b.Property(x => x.Sort).HasMaxLength(50); |
||||
b.Property(x => x.TargetUrl).HasMaxLength(500); |
||||
b.Property(x => x.PermissionKey).HasMaxLength(100); |
||||
|
||||
b.HasIndex(x => new { x.PermissionKey }); |
||||
}); |
||||
|
||||
builder.Entity<MenuGrant>(b => |
||||
{ |
||||
b.ToTable(MenuManagementDbProperties.DbTablePrefix + "MenuGrants", MenuManagementDbProperties.DbSchema); |
||||
b.ConfigureByConvention(); |
||||
|
||||
b.Property(x => x.MenuId).IsRequired(); |
||||
b.Property(x => x.ProviderName).HasMaxLength(MenuGrantConsts.MaxProviderNameLength).IsRequired(); |
||||
b.Property(x => x.ProviderKey).HasMaxLength(MenuGrantConsts.MaxProviderKeyLength).IsRequired(); |
||||
|
||||
b.HasIndex(x => new { x.MenuId, x.ProviderName, x.ProviderKey }); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
using Microsoft.Extensions.DependencyInjection; |
||||
using Volo.Abp.EntityFrameworkCore; |
||||
using Volo.Abp.Modularity; |
||||
using Volo.Abp.PermissionManagement.EntityFrameworkCore; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement.EntityFrameworkCore; |
||||
|
||||
[DependsOn( |
||||
typeof(AbpPermissionManagementEntityFrameworkCoreModule), |
||||
typeof(MenuManagementDomainModule), |
||||
typeof(AbpEntityFrameworkCoreModule) |
||||
)] |
||||
public class MenuManagementEntityFrameworkCoreModule : AbpModule |
||||
{ |
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
||||
context.Services.AddAbpDbContext<MenuManagementDbContext>(options => |
||||
{ |
||||
options.AddRepository<Menu, MenuRepository>(); |
||||
}); |
||||
} |
||||
} |
@ -0,0 +1,66 @@
|
||||
using Microsoft.EntityFrameworkCore; |
||||
using Sanhe.Abp.MenuManagement.EntityFrameworkCore; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Linq; |
||||
using System.Threading; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
using Volo.Abp.EntityFrameworkCore; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuGrantRepository : EfCoreRepository<IMenuManagementDbContext, MenuGrant, Guid>, IMenuGrantRepository |
||||
{ |
||||
public MenuGrantRepository(IDbContextProvider<IMenuManagementDbContext> dbContextProvider) : base(dbContextProvider) |
||||
{ |
||||
|
||||
} |
||||
|
||||
public virtual async Task<MenuGrant> FindAsync(Guid menuId, string providerName, string providerKey, |
||||
CancellationToken cancellationToken = default) |
||||
{ |
||||
return await (await GetDbSetAsync()) |
||||
.FirstOrDefaultAsync(s => |
||||
s.MenuId == menuId && |
||||
s.ProviderName == providerName && |
||||
s.ProviderKey == providerKey, |
||||
GetCancellationToken(cancellationToken) |
||||
); |
||||
} |
||||
|
||||
public virtual async Task<List<MenuGrant>> GetListAsync(string providerName, string providerKey, |
||||
CancellationToken cancellationToken = default) |
||||
{ |
||||
return await (await GetDbSetAsync()) |
||||
.Where(x => x.ProviderKey == providerKey && x.ProviderName == providerName) |
||||
.ToListAsync(GetCancellationToken(cancellationToken)); |
||||
|
||||
//return await ( |
||||
// from g in DbSet |
||||
// join m in DbContext.Set<Menu>() on g.MenuId equals m.Id |
||||
// where g.ProviderKey == providerKey && g.ProviderName == providerName |
||||
// select new MenuGrantInfoDto |
||||
// { |
||||
// Id = g.MenuId, |
||||
// Name = m.Name, |
||||
// DisplayName = m.DisplayName, |
||||
// PermissionKey = m.PermissionKey, |
||||
// IsGranted = true |
||||
// } |
||||
//).ToListAsync(GetCancellationToken(cancellationToken)); |
||||
} |
||||
|
||||
public virtual async Task<List<MenuGrant>> GetGrantByMenuIdAsync(Guid menuId, bool noTracking = true) |
||||
{ |
||||
var query = (await GetDbSetAsync()).Where(x => x.MenuId == menuId); |
||||
|
||||
if (noTracking) |
||||
{ |
||||
query = query.AsNoTracking(); |
||||
} |
||||
|
||||
return await query.ToListAsync(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,25 @@
|
||||
using Microsoft.EntityFrameworkCore; |
||||
using Sanhe.Abp.MenuManagement.EntityFrameworkCore; |
||||
using System; |
||||
using System.Linq; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
||||
using Volo.Abp.EntityFrameworkCore; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
public class MenuRepository : EfCoreRepository<IMenuManagementDbContext, Menu, Guid>, IMenuRepository |
||||
{ |
||||
public MenuRepository(IDbContextProvider<IMenuManagementDbContext> dbContextProvider) : base(dbContextProvider) |
||||
{ |
||||
|
||||
} |
||||
|
||||
public override async Task<IQueryable<Menu>> WithDetailsAsync() |
||||
{ |
||||
var queryable = await GetQueryableAsync(); |
||||
|
||||
return queryable.Include(x => x.Parent); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
||||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
||||
</Weavers> |
@ -0,0 +1,16 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
||||
<Import Project="..\..\..\configureawait.props" /> |
||||
<Import Project="..\..\..\common.props" /> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>net6.0</TargetFramework> |
||||
<RootNamespace /> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Volo.Abp.AspNetCore.Mvc" Version="$(VoloAbpVersion)" /> |
||||
<PackageReference Include="Volo.Abp.PermissionManagement.HttpApi" Version="$(VoloAbpVersion)" /> |
||||
<ProjectReference Include="..\Sanhe.Abp.MenuManagement.Application.Contracts\Sanhe.Abp.MenuManagement.Application.Contracts.csproj" /> |
||||
</ItemGroup> |
||||
</Project> |
@ -0,0 +1,57 @@
|
||||
using Microsoft.AspNetCore.Mvc; |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp; |
||||
using Volo.Abp.Application.Dtos; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
[RemoteService] |
||||
[Route("api/menu-management/menus")] |
||||
public class MenuController : MenuManagementController, IMenuAppService |
||||
{ |
||||
private readonly IMenuAppService _menuAppService; |
||||
|
||||
public MenuController(IMenuAppService menuAppService) |
||||
{ |
||||
_menuAppService = menuAppService; |
||||
} |
||||
|
||||
[HttpGet("{id}")] |
||||
public virtual Task<MenuDto> GetAsync(Guid id) |
||||
{ |
||||
return _menuAppService.GetAsync(id); |
||||
} |
||||
|
||||
[HttpGet] |
||||
public virtual Task<PagedResultDto<MenuDto>> GetListAsync(MenuRequestDto input) |
||||
{ |
||||
return _menuAppService.GetListAsync(input); |
||||
} |
||||
|
||||
[HttpPost] |
||||
public virtual Task<MenuDto> CreateAsync(CreateOrUpdateMenuDto input) |
||||
{ |
||||
return _menuAppService.CreateAsync(input); |
||||
} |
||||
|
||||
[HttpPut("{id}")] |
||||
public virtual Task<MenuDto> UpdateAsync(Guid id, CreateOrUpdateMenuDto input) |
||||
{ |
||||
return _menuAppService.UpdateAsync(id, input); |
||||
} |
||||
|
||||
[HttpDelete("{id}")] |
||||
public virtual Task DeleteAsync(Guid id) |
||||
{ |
||||
return _menuAppService.DeleteAsync(id); |
||||
} |
||||
|
||||
[HttpGet("auth-policies")] |
||||
public virtual Task<List<AuthPolicyDto>> GetAuthPolicies() |
||||
{ |
||||
return _menuAppService.GetAuthPolicies(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,39 @@
|
||||
using Microsoft.AspNetCore.Mvc; |
||||
using System.Threading.Tasks; |
||||
using Volo.Abp; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement |
||||
{ |
||||
/// <summary> |
||||
/// 菜单分配 |
||||
/// </summary> |
||||
[RemoteService] |
||||
[Route("api/menu-management/menu-grant")] |
||||
public class MenuGrantController : MenuManagementController, IMenuGrantAppService |
||||
{ |
||||
private readonly IMenuGrantAppService _menuGrantAppService; |
||||
|
||||
public MenuGrantController(IMenuGrantAppService menuGrantAppService) |
||||
{ |
||||
_menuGrantAppService = menuGrantAppService; |
||||
} |
||||
|
||||
[HttpGet("list")] |
||||
public virtual Task<GetMenuResultDto> GetListAsync() |
||||
{ |
||||
return _menuGrantAppService.GetListAsync(); |
||||
} |
||||
|
||||
[HttpGet] |
||||
public virtual Task<GetMenuGrantListResultDto> GetAsync(string providerName, string providerKey) |
||||
{ |
||||
return _menuGrantAppService.GetAsync(providerName, providerKey); |
||||
} |
||||
|
||||
[HttpPut] |
||||
public virtual Task UpdateAsync(string providerName, string providerKey, UpdateMenuGrantsDto input) |
||||
{ |
||||
return _menuGrantAppService.UpdateAsync(providerName, providerKey, input); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,12 @@
|
||||
using Sanhe.Abp.MenuManagement.Localization; |
||||
using Volo.Abp.AspNetCore.Mvc; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
public abstract class MenuManagementController : AbpControllerBase |
||||
{ |
||||
protected MenuManagementController() |
||||
{ |
||||
LocalizationResource = typeof(MenuManagementResource); |
||||
} |
||||
} |
@ -0,0 +1,34 @@
|
||||
using Localization.Resources.AbpUi; |
||||
using Microsoft.Extensions.DependencyInjection; |
||||
using Sanhe.Abp.MenuManagement.Localization; |
||||
using Volo.Abp.AspNetCore.Mvc; |
||||
using Volo.Abp.Localization; |
||||
using Volo.Abp.Modularity; |
||||
using Volo.Abp.PermissionManagement.HttpApi; |
||||
|
||||
namespace Sanhe.Abp.MenuManagement; |
||||
|
||||
[DependsOn( |
||||
typeof(AbpPermissionManagementHttpApiModule), |
||||
typeof(MenuManagementApplicationContractsModule), |
||||
typeof(AbpAspNetCoreMvcModule))] |
||||
public class MenuManagementHttpApiModule : AbpModule |
||||
{ |
||||
public override void PreConfigureServices(ServiceConfigurationContext context) |
||||
{ |
||||
PreConfigure<IMvcBuilder>(mvcBuilder => |
||||
{ |
||||
mvcBuilder.AddApplicationPartIfNotExists(typeof(MenuManagementHttpApiModule).Assembly); |
||||
}); |
||||
} |
||||
|
||||
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
{ |
||||
Configure<AbpLocalizationOptions>(options => |
||||
{ |
||||
options.Resources |
||||
.Get<MenuManagementResource>() |
||||
.AddBaseTypes(typeof(AbpUiResource)); |
||||
}); |
||||
} |
||||
} |
Loading…
Reference in new issue