diff --git a/aspnet-core/LINGYUN.MicroService.sln b/aspnet-core/LINGYUN.MicroService.sln index b907ce0f3..dd7b8e2b1 100644 --- a/aspnet-core/LINGYUN.MicroService.sln +++ b/aspnet-core/LINGYUN.MicroService.sln @@ -223,7 +223,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Features.Valida EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Features.Validation.Redis.Tests", "tests\LINGYUN.Abp.Features.Validation.Redis.Tests\LINGYUN.Abp.Features.Validation.Redis.Tests.csproj", "{F12F4645-C0FE-4129-8C71-65B4039DC445}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Features.Validation.Tests", "tests\LINGYUN.Abp.Features.Validation.Tests\LINGYUN.Abp.Features.Validation.Tests.csproj", "{C457FA70-8732-44B8-A018-C96D14025D4B}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Features.Validation.Tests", "tests\LINGYUN.Abp.Features.Validation.Tests\LINGYUN.Abp.Features.Validation.Tests.csproj", "{C457FA70-8732-44B8-A018-C96D14025D4B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "features", "features", "{08BD73E6-72CE-4A8A-896D-2DFFF4D7D2F8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.FeatureManagement.Client", "modules\features\LINGYUN.Abp.FeatureManagement.Client\LINGYUN.Abp.FeatureManagement.Client.csproj", "{7071E78B-755B-410A-830B-AA05D7168944}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Features.Client", "modules\features\LINGYUN.Abp.Features.Client\LINGYUN.Abp.Features.Client.csproj", "{87B65CBD-0FF4-4FB5-9ABC-161911A71179}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -599,6 +605,14 @@ Global {C457FA70-8732-44B8-A018-C96D14025D4B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C457FA70-8732-44B8-A018-C96D14025D4B}.Release|Any CPU.ActiveCfg = Release|Any CPU {C457FA70-8732-44B8-A018-C96D14025D4B}.Release|Any CPU.Build.0 = Release|Any CPU + {7071E78B-755B-410A-830B-AA05D7168944}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7071E78B-755B-410A-830B-AA05D7168944}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7071E78B-755B-410A-830B-AA05D7168944}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7071E78B-755B-410A-830B-AA05D7168944}.Release|Any CPU.Build.0 = Release|Any CPU + {87B65CBD-0FF4-4FB5-9ABC-161911A71179}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {87B65CBD-0FF4-4FB5-9ABC-161911A71179}.Debug|Any CPU.Build.0 = Debug|Any CPU + {87B65CBD-0FF4-4FB5-9ABC-161911A71179}.Release|Any CPU.ActiveCfg = Release|Any CPU + {87B65CBD-0FF4-4FB5-9ABC-161911A71179}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -712,6 +726,9 @@ Global {D3E65610-4167-4235-9C9D-1E1FAD4C0CE6} = {8AC72641-30D3-4ACF-89FA-808FADC55C2E} {F12F4645-C0FE-4129-8C71-65B4039DC445} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F} {C457FA70-8732-44B8-A018-C96D14025D4B} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F} + {08BD73E6-72CE-4A8A-896D-2DFFF4D7D2F8} = {C5CAD011-DF84-4914-939C-0C029DCEF26F} + {7071E78B-755B-410A-830B-AA05D7168944} = {08BD73E6-72CE-4A8A-896D-2DFFF4D7D2F8} + {87B65CBD-0FF4-4FB5-9ABC-161911A71179} = {08BD73E6-72CE-4A8A-896D-2DFFF4D7D2F8} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} diff --git a/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN.Abp.FeatureManagement.Client.csproj b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN.Abp.FeatureManagement.Client.csproj new file mode 100644 index 000000000..7b8ebf8ed --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN.Abp.FeatureManagement.Client.csproj @@ -0,0 +1,24 @@ + + + + + + netstandard2.0 + + + + + + + + + + + + + + + + + + diff --git a/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/AbpFeatureManagementClientModule.cs b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/AbpFeatureManagementClientModule.cs new file mode 100644 index 000000000..c6c00aa47 --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/AbpFeatureManagementClientModule.cs @@ -0,0 +1,25 @@ +using LINGYUN.Abp.FeatureManagement.Client; +using LINGYUN.Abp.FeatureManagement.Client.Permissions; +using LINGYUN.Abp.Features.Client; +using Volo.Abp.FeatureManagement; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.FeatureManagement +{ + [DependsOn( + typeof(AbpFeaturesClientModule), + typeof(AbpFeatureManagementDomainModule) + )] + public class AbpFeatureManagementClientModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.Providers.Add(); + + options.ProviderPolicies[ClientFeatureValueProvider.ProviderName] = ClientFeaturePermissionNames.Clients.ManageFeatures; + }); + } + } +} diff --git a/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/ClientFeatureManagementProvider.cs b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/ClientFeatureManagementProvider.cs new file mode 100644 index 000000000..477b41cbe --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/ClientFeatureManagementProvider.cs @@ -0,0 +1,33 @@ +using LINGYUN.Abp.Features.Client; +using Volo.Abp.Clients; +using Volo.Abp.DependencyInjection; +using Volo.Abp.FeatureManagement; + +namespace LINGYUN.Abp.FeatureManagement.Client +{ + + public class ClientFeatureManagementProvider : FeatureManagementProvider, ITransientDependency + { + public override string Name => ClientFeatureValueProvider.ProviderName; + + protected ICurrentClient CurrentClient; + + public ClientFeatureManagementProvider( + ICurrentClient currentClient, + IFeatureManagementStore store) + : base(store) + { + CurrentClient = currentClient; + } + + protected override string NormalizeProviderKey(string providerKey) + { + if (providerKey != null) + { + return providerKey; + } + + return CurrentClient.Id; + } + } +} diff --git a/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/Permissions/ClientFeaturePermissionDefinitionProvider.cs b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/Permissions/ClientFeaturePermissionDefinitionProvider.cs new file mode 100644 index 000000000..495f23b40 --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/Permissions/ClientFeaturePermissionDefinitionProvider.cs @@ -0,0 +1,33 @@ +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.FeatureManagement.Localization; +using Volo.Abp.Localization; + +namespace LINGYUN.Abp.FeatureManagement.Client.Permissions +{ + public class ClientFeaturePermissionDefinitionProvider : PermissionDefinitionProvider + { + public override void Define(IPermissionDefinitionContext context) + { + var identityServerGroup = context.GetGroupOrNull(ClientFeaturePermissionNames.GroupName); + if (identityServerGroup == null) + { + identityServerGroup = context + .AddGroup( + name: ClientFeaturePermissionNames.GroupName, + displayName: L("Permissions:IdentityServer"), + multiTenancySide: Volo.Abp.MultiTenancy.MultiTenancySides.Host); + } + identityServerGroup + .AddPermission( + name: ClientFeaturePermissionNames.Clients.ManageFeatures, + displayName: L("Permissions:ManageFeatures"), + multiTenancySide: Volo.Abp.MultiTenancy.MultiTenancySides.Host) + .WithProviders(ClientPermissionValueProvider.ProviderName); + } + + protected virtual LocalizableString L(string name) + { + return LocalizableString.Create(name); + } + } +} diff --git a/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/Permissions/ClientFeaturePermissionNames.cs b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/Permissions/ClientFeaturePermissionNames.cs new file mode 100644 index 000000000..d0b1a7b7e --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Client/Permissions/ClientFeaturePermissionNames.cs @@ -0,0 +1,16 @@ +namespace LINGYUN.Abp.FeatureManagement.Client.Permissions +{ + public class ClientFeaturePermissionNames + { + public const string GroupName = "IdentityServer"; + + public static class Clients + { + public const string Default = GroupName + ".Clients"; + /// + /// 管理功能权限 + /// + public const string ManageFeatures = Default + ".ManageFeatures"; + } + } +} diff --git a/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/ClientFeatureManagerExtensions.cs b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/ClientFeatureManagerExtensions.cs new file mode 100644 index 000000000..60f929f79 --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/ClientFeatureManagerExtensions.cs @@ -0,0 +1,36 @@ +using JetBrains.Annotations; +using LINGYUN.Abp.Features.Client; +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.FeatureManagement; + +namespace LINGYUN.Abp.FeatureManagement +{ + public static class ClientFeatureManagerExtensions + { + public static Task GetOrNullForClientAsync(this IFeatureManager featureManager, [NotNull] string name, string clientId, bool fallback = true) + { + return featureManager.GetOrNullAsync(name, ClientFeatureValueProvider.ProviderName, clientId, fallback); + } + + public static Task> GetAllForClientAsync(this IFeatureManager featureManager, string clientId, bool fallback = true) + { + return featureManager.GetAllAsync(ClientFeatureValueProvider.ProviderName, clientId, fallback); + } + + public static Task GetOrNullWithProviderForClientAsync(this IFeatureManager featureManager, [NotNull] string name, string clientId, bool fallback = true) + { + return featureManager.GetOrNullWithProviderAsync(name, ClientFeatureValueProvider.ProviderName, clientId, fallback); + } + + public static Task> GetAllWithProviderForClientAsync(this IFeatureManager featureManager, string clientId, bool fallback = true) + { + return featureManager.GetAllWithProviderAsync(ClientFeatureValueProvider.ProviderName, clientId, fallback); + } + + public static Task SetForEditionAsync(this IFeatureManager featureManager, string clientId, [NotNull] string name, [CanBeNull] string value, bool forceToSet = false) + { + return featureManager.SetAsync(name, value, ClientFeatureValueProvider.ProviderName, clientId, forceToSet); + } + } +} diff --git a/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Localization/Client/en.json b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Localization/Client/en.json new file mode 100644 index 000000000..8c72ee646 --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Localization/Client/en.json @@ -0,0 +1,7 @@ +{ + "culture": "en", + "texts": { + "Permissions:IdentityServer": "IdentityServer", + "Permissions:ManageFeatures": "Manage features" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Localization/Client/zh-Hans.json b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Localization/Client/zh-Hans.json new file mode 100644 index 000000000..7f7181c99 --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.FeatureManagement.Client/LINGYUN/Abp/FeatureManagement/Localization/Client/zh-Hans.json @@ -0,0 +1,7 @@ +{ + "culture": "zh-Hans", + "texts": { + "Permissions:IdentityServer": "IdentityServer管理", + "ManageFeatures": "管理功能" + } +} \ No newline at end of file diff --git a/aspnet-core/modules/features/LINGYUN.Abp.Features.Client/LINGYUN.Abp.Features.Client.csproj b/aspnet-core/modules/features/LINGYUN.Abp.Features.Client/LINGYUN.Abp.Features.Client.csproj new file mode 100644 index 000000000..69acd1542 --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.Features.Client/LINGYUN.Abp.Features.Client.csproj @@ -0,0 +1,14 @@ + + + + + + netstandard2.0 + + + + + + + + diff --git a/aspnet-core/modules/features/LINGYUN.Abp.Features.Client/LINGYUN/Abp/Features/Client/AbpFeaturesClientModule.cs b/aspnet-core/modules/features/LINGYUN.Abp.Features.Client/LINGYUN/Abp/Features/Client/AbpFeaturesClientModule.cs new file mode 100644 index 000000000..6b5b6475f --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.Features.Client/LINGYUN/Abp/Features/Client/AbpFeaturesClientModule.cs @@ -0,0 +1,18 @@ +using Volo.Abp.Features; +using Volo.Abp.Modularity; + +namespace LINGYUN.Abp.Features.Client +{ + [DependsOn( + typeof(AbpFeaturesModule))] + public class AbpFeaturesClientModule : AbpModule + { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.ValueProviders.Add(); + }); + } + } +} diff --git a/aspnet-core/modules/features/LINGYUN.Abp.Features.Client/LINGYUN/Abp/Features/Client/ClientFeatureValueProvider.cs b/aspnet-core/modules/features/LINGYUN.Abp.Features.Client/LINGYUN/Abp/Features/Client/ClientFeatureValueProvider.cs new file mode 100644 index 000000000..14ac3ea22 --- /dev/null +++ b/aspnet-core/modules/features/LINGYUN.Abp.Features.Client/LINGYUN/Abp/Features/Client/ClientFeatureValueProvider.cs @@ -0,0 +1,33 @@ +using System.Threading.Tasks; +using Volo.Abp.Clients; +using Volo.Abp.Features; + +namespace LINGYUN.Abp.Features.Client +{ + public class ClientFeatureValueProvider : FeatureValueProvider + { + public const string ProviderName = "C"; + + public override string Name => ProviderName; + + protected ICurrentClient CurrentClient; + + public ClientFeatureValueProvider( + IFeatureStore featureStore, + ICurrentClient currentClient) + : base(featureStore) + { + CurrentClient = currentClient; + } + + public override async Task GetOrNullAsync(FeatureDefinition feature) + { + if (!CurrentClient.IsAuthenticated) + { + return null; + } + + return await FeatureStore.GetOrNullAsync(feature.Name, Name, CurrentClient.Id); + } + } +} diff --git a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/AbpIdentityServerPermissionDefinitionProvider.cs b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/AbpIdentityServerPermissionDefinitionProvider.cs index 1a95296ad..6b19a03e1 100644 --- a/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/AbpIdentityServerPermissionDefinitionProvider.cs +++ b/aspnet-core/modules/identityServer/LINGYUN.Abp.IdentityServer.Application.Contracts/LINGYUN/Abp/IdentityServer/AbpIdentityServerPermissionDefinitionProvider.cs @@ -11,8 +11,18 @@ namespace LINGYUN.Abp.IdentityServer { // TODO: 身份认证服务器应该只能主机管辖 // 增加 MultiTenancySides.Host - var identityServerGroup = context.AddGroup(AbpIdentityServerPermissions.GroupName, L("Permissions:IdentityServer"), MultiTenancySides.Host); + // var identityServerGroup = context.AddGroup(AbpIdentityServerPermissions.GroupName, L("Permissions:IdentityServer"), MultiTenancySides.Host); + // 与 LINGYUN.Abp.FeatureManagement.Client 模块搭配,这样干可以不依赖于模块优先级 + var identityServerGroup = context.GetGroupOrNull(AbpIdentityServerPermissions.GroupName); + if (identityServerGroup == null) + { + identityServerGroup = context + .AddGroup( + name: AbpIdentityServerPermissions.GroupName, + displayName: L("Permissions:IdentityServer"), + multiTenancySide: MultiTenancySides.Host); + } // 客户端权限 var clientPermissions = identityServerGroup.AddPermission(AbpIdentityServerPermissions.Clients.Default, L("Permissions:Clients"), MultiTenancySides.Host); clientPermissions.AddChild(AbpIdentityServerPermissions.Clients.Create, L("Permissions:Create"), MultiTenancySides.Host);