Browse Source

Merge pull request #1166 from colinin/some-commits

Some commits
pull/1171/head
yx lin 12 months ago
committed by GitHub
parent
commit
5112d9a222
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN.Abp.DataProtection.Abstractions.csproj
  2. 5
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AbpDataProtectionAbstractionsModule.cs
  3. 20
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AsyncLocalCurrentDataAccessAccessor.cs
  4. 37
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessEntityAuthCreateEvent.cs
  5. 1
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResource.cs
  6. 4
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResourceChangeEvent.cs
  7. 28
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessScope.cs
  8. 31
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessStrategy.cs
  9. 35
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessStrategyState.cs
  10. 14
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataProtectedAttribute.cs
  11. 6
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DisableDataProtectedAttribute.cs
  12. 6
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/ICurrentDataAccessAccessor.cs
  13. 9
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataAccessScope.cs
  14. 6
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtected.cs
  15. 8
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/en.json
  16. 8
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/zh-Hans.json
  17. 3
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/FodyWeavers.xml
  18. 24
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN.Abp.DataProtection.Application.Contracts.csproj
  19. 12
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationContractsModule.cs
  20. 7
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityEnumInfoDto.cs
  21. 29
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityPropertyInfoDto.cs
  22. 17
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoDto.cs
  23. 6
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoGetInput.cs
  24. 14
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/IEntityTypeInfoAppService.cs
  25. 3
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/FodyWeavers.xml
  26. 25
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN.Abp.DataProtection.Application.csproj
  27. 13
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationModule.cs
  28. 47
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/EntityTypeInfoAppService.cs
  29. 10
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/System/NullableTypeExtensions.cs
  30. 20
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWritePropertiesInterceptor.cs
  31. 16
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs
  32. 54
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContextModelBuilderExtensions.cs
  33. 7
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionEntityFrameworkCoreModule.cs
  34. 172
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataAccessStrategyFilterBuilder.cs
  35. 163
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepository.cs
  36. 6
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs
  37. 5
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionOptions.cs
  38. 7
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessKeywordContributorContext.cs
  39. 25
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessResourceCacheInvalidator.cs
  40. 12
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyContributorContext.cs
  41. 16
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyFilterBuildResult.cs
  42. 66
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyFilterBuilderBase.cs
  43. 36
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyStateProvider.cs
  44. 33
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAuthBase.cs
  45. 22
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptor.cs
  46. 16
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityPropertyResultBuilder.cs
  47. 34
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityTypeFilterBuilder.cs
  48. 3
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessKeywordContributor.cs
  49. 9
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyContributor.cs
  50. 13
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyFilterBuilder.cs
  51. 8
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyStateProvider.cs
  52. 57
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/InMemoryDataProtectedResourceStore.cs
  53. 9
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Keywords/DataAccessCurrentUserContributor.cs
  54. 44
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataAccessStrategyStateCacheItem.cs
  55. 5
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceCache.cs
  56. 7
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceCacheItem.cs
  57. 12
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceStore.cs
  58. 42
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedStrategyStateCache.cs
  59. 38
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedStrategyStateStore.cs
  60. 5
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedResourceCache.cs
  61. 2
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedResourceStore.cs
  62. 12
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedStrategyStateCache.cs
  63. 12
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedStrategyStateStore.cs
  64. 3
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessClientIdContributor.cs
  65. 1
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessOrganizationUnitContributor.cs
  66. 3
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessRoleNameContributor.cs
  67. 39
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessStrategyRoleNameContributor.cs
  68. 3
      aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessUserIdContributor.cs
  69. 5328
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250402083655_Upgrade-Abp-Framework-To-9.1.1.Designer.cs
  70. 41
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250402083655_Upgrade-Abp-Framework-To-9.1.1.cs
  71. 5328
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250403031044_Change-Auth-Data-Type.Designer.cs
  72. 38
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250403031044_Change-Auth-Data-Type.cs
  73. 5388
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250403085116_Add-Subject-Strategy.Designer.cs
  74. 49
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250403085116_Add-Subject-Strategy.cs
  75. 5442
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250407032556_Add-Book-Auth.Designer.cs
  76. 85
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250407032556_Add-Book-Auth.cs
  77. 124
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/SingleMigrationsDbContextModelSnapshot.cs
  78. 21
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/ApplicationSingleDataSeederWorker.cs
  79. 29
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/ClientDataSeederContributor.cs
  80. 53
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/IdentityDataSeedContributor.cs
  81. 2
      aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsEntityFrameworkCoreModule.cs
  82. 11
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/SubjectStrategyDto.cs
  83. 15
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/SubjectStrategyGetInput.cs
  84. 20
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/SubjectStrategySetInput.cs
  85. 11
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/ISubjectStrategyAppService.cs
  86. 3
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionDefinitionProvider.cs
  87. 6
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionNames.cs
  88. 2
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementApplicationMappingProfile.cs
  89. 2
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleAppService.cs
  90. 2
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleAppService.cs
  91. 63
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/SubjectStrategyAppService.cs
  92. 6
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/System/Linq/Expressions/ExpressionFuncExtensions.cs
  93. 2
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/Localization/Resources/en.json
  94. 2
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/Localization/Resources/zh-Hans.json
  95. 7
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/SubjectStrategyConsts.cs
  96. 34
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataAccessStrategyStateSynchronizer.cs
  97. 14
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/ISubjectStrategyRepository.cs
  98. 41
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/SubjectStrategy.cs
  99. 15
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementDbContextModelCreatingExtensions.cs
  100. 2
      aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementEntityFrameworkCoreModule.cs

1
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN.Abp.DataProtection.Abstractions.csproj

@ -26,6 +26,7 @@
<ItemGroup>
<PackageReference Include="Volo.Abp.ObjectExtending" />
<PackageReference Include="Volo.Abp.Localization" />
<PackageReference Include="Volo.Abp.MultiTenancy" />
</ItemGroup>
</Project>

5
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AbpDataProtectionAbstractionsModule.cs

@ -1,17 +1,22 @@
using LINGYUN.Abp.DataProtection.Localization;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Localization;
using Volo.Abp.Modularity;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;
using Volo.Abp.VirtualFileSystem;
namespace LINGYUN.Abp.DataProtection;
[DependsOn(typeof(AbpLocalizationModule))]
[DependsOn(typeof(AbpMultiTenancyModule))]
[DependsOn(typeof(AbpObjectExtendingModule))]
public class AbpDataProtectionAbstractionsModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddSingleton<ICurrentDataAccessAccessor>(AsyncLocalCurrentDataAccessAccessor.Instance);
Configure<AbpVirtualFileSystemOptions>(options =>
{
options.FileSets.AddEmbedded<AbpDataProtectionAbstractionsModule>();

20
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AsyncLocalCurrentDataAccessAccessor.cs

@ -0,0 +1,20 @@
using System.Threading;
namespace LINGYUN.Abp.DataProtection;
public class AsyncLocalCurrentDataAccessAccessor : ICurrentDataAccessAccessor
{
public static AsyncLocalCurrentDataAccessAccessor Instance { get; } = new();
public DataAccessOperation[] Current
{
get => _currentScope.Value;
set => _currentScope.Value = value;
}
private readonly AsyncLocal<DataAccessOperation[]> _currentScope;
private AsyncLocalCurrentDataAccessAccessor()
{
_currentScope = new AsyncLocal<DataAccessOperation[]>();
}
}

37
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessEntityAuthCreateEvent.cs

@ -0,0 +1,37 @@
using System;
using Volo.Abp.EventBus;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.DataProtection;
[Serializable]
[EventName("abp.data_protection.entity_auth_created")]
public class DataAccessEntityAuthCreateEvent : IMultiTenant
{
public Guid? TenantId { get; set; }
public string[] EntityKeys { get; set; }
public string EntityKeyType { get; set; }
public string EntityType { get; set; }
public string[] Roles { get; set; }
public string[] OrganizationUnits { get; set; }
public DataAccessEntityAuthCreateEvent()
{
}
public DataAccessEntityAuthCreateEvent(
string entityType,
string entityKeyType,
string[] entityKeys,
string[] roles = null,
string[] organizationUnits = null,
Guid? tenantId = null)
{
EntityType = entityType;
EntityKeyType = entityKeyType;
EntityKeys = entityKeys;
EntityType = entityType;
Roles = roles;
OrganizationUnits = organizationUnits;
TenantId = tenantId;
}
}

1
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResource.cs

@ -53,6 +53,7 @@ public class DataAccessResource
EntityTypeFullName = entityTypeFullName;
Operation = operation;
FilterGroup = filterGroup;
AccessedProperties = new List<string>();
}
}

4
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResourceChangeEvent.cs

@ -7,14 +7,16 @@ namespace LINGYUN.Abp.DataProtection;
[EventName("abp.data_protection.resource_changed")]
public class DataAccessResourceChangeEvent
{
public bool IsEnabled { get; set; }
public DataAccessResource Resource { get; set; }
public DataAccessResourceChangeEvent()
{
}
public DataAccessResourceChangeEvent(DataAccessResource resource)
public DataAccessResourceChangeEvent(bool isEnabled, DataAccessResource resource)
{
IsEnabled = isEnabled;
Resource = resource;
}
}

28
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessScope.cs

@ -0,0 +1,28 @@
using System;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.DataProtection;
public class DataAccessScope : IDataAccessScope, ITransientDependency
{
public DataAccessOperation[] Operations => _currentDataAccessAccessor.Current;
private readonly ICurrentDataAccessAccessor _currentDataAccessAccessor;
public DataAccessScope(ICurrentDataAccessAccessor currentDataAccessAccessor)
{
_currentDataAccessAccessor = currentDataAccessAccessor;
}
public IDisposable BeginScope(DataAccessOperation[] operations = null)
{
var parentScope = _currentDataAccessAccessor.Current;
_currentDataAccessAccessor.Current = operations;
return new DisposeAction<ValueTuple<ICurrentDataAccessAccessor, DataAccessOperation[]>>(static (state) =>
{
var (currentDataAccessAccessor, parentScope) = state;
currentDataAccessAccessor.Current = parentScope;
}, (_currentDataAccessAccessor, parentScope));
}
}

31
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessStrategy.cs

@ -0,0 +1,31 @@
namespace LINGYUN.Abp.DataProtection;
/// <summary>
/// 数据访问策略
/// </summary>
public enum DataAccessStrategy
{
/// <summary>
/// 可以访问所有数据
/// </summary>
All,
/// <summary>
/// 自定义规则
/// </summary>
Custom,
/// <summary>
/// 仅当前用户
/// </summary>
CurrentUser,
/// <summary>
/// 仅当前用户角色
/// </summary>
CurrentRoles,
/// <summary>
/// 仅当前用户组织机构
/// </summary>
CurrentOrganizationUnits,
/// <summary>
/// 仅当前用户组织机构及下级机构
/// </summary>
CurrentAndSubOrganizationUnits,
}

35
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessStrategyState.cs

@ -0,0 +1,35 @@
using System;
namespace LINGYUN.Abp.DataProtection;
[Serializable]
public class DataAccessStrategyState
{
/// <summary>
/// 权限主体
/// </summary>
public string SubjectName { get; set; }
/// <summary>
/// 权限主体标识
/// </summary>
public string[] SubjectKeys { get; set; }
/// <summary>
/// 权限策略
/// </summary>
public DataAccessStrategy Strategy { get; set; }
public DataAccessStrategyState()
{
}
public DataAccessStrategyState(
string subjectName,
string[] subjectKeys,
DataAccessStrategy strategy)
{
SubjectName = subjectName;
SubjectKeys = subjectKeys;
Strategy = strategy;
}
}

14
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataProtectedAttribute.cs

@ -2,16 +2,20 @@
namespace LINGYUN.Abp.DataProtection;
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)]
public class DataProtectedAttribute : Attribute
{
public DataAccessOperation Operation { get; }
public DataProtectedAttribute() : this(DataAccessOperation.Read)
public DataAccessOperation[] Operations { get; }
public DataProtectedAttribute() : this(
DataAccessOperation.Read,
DataAccessOperation.Write,
DataAccessOperation.Delete)
{
}
public DataProtectedAttribute(DataAccessOperation operation)
public DataProtectedAttribute(params DataAccessOperation[] operations)
{
Operation = operation;
Operations = operations;
}
}

6
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DisableDataProtectedAttribute.cs

@ -5,13 +5,7 @@ namespace LINGYUN.Abp.DataProtection;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false)]
public class DisableDataProtectedAttribute : Attribute
{
public DataAccessOperation? Operation { get; }
public DisableDataProtectedAttribute()
{
}
public DisableDataProtectedAttribute(DataAccessOperation operation)
{
Operation = operation;
}
}

6
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/ICurrentDataAccessAccessor.cs

@ -0,0 +1,6 @@
namespace LINGYUN.Abp.DataProtection;
public interface ICurrentDataAccessAccessor
{
DataAccessOperation[] Current { get; set; }
}

9
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataAccessScope.cs

@ -0,0 +1,9 @@
using System;
namespace LINGYUN.Abp.DataProtection;
public interface IDataAccessScope
{
DataAccessOperation[] Operations { get; }
IDisposable BeginScope(DataAccessOperation[] operations = null);
}

6
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtected.cs

@ -1,8 +1,8 @@
using Volo.Abp.Data;
using System;
namespace LINGYUN.Abp.DataProtection;
public interface IDataProtected : IHasExtraProperties
public interface IDataProtected
{
Guid? CreatorId { get; }
}

8
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/en.json

@ -5,6 +5,12 @@
"DisplayName:LastModifierId": "Last Modifier Id",
"DisplayName:LastModificationTime": "Last Modification Time",
"DisplayName:CreatorId": "Creator Id",
"DisplayName:CreationTime": "Creation Time"
"DisplayName:CreationTime": "Creation Time",
"DataAccessStrategy:All": "All",
"DataAccessStrategy:Custom": "Custom",
"DataAccessStrategy:CurrentUser": "Current User",
"DataAccessStrategy:CurrentRoles": "Current Roles",
"DataAccessStrategy:CurrentOrganizationUnits": "Current Organization Units",
"DataAccessStrategy:CurrentAndSubOrganizationUnits": "Current And Sub Organization Units"
}
}

8
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/zh-Hans.json

@ -5,6 +5,12 @@
"DisplayName:LastModifierId": "上次修改人",
"DisplayName:LastModificationTime": "上次修改时间",
"DisplayName:CreatorId": "创建人",
"DisplayName:CreationTime": "创建时间"
"DisplayName:CreationTime": "创建时间",
"DataAccessStrategy:All": "可以访问所有数据",
"DataAccessStrategy:Custom": "自定义规则",
"DataAccessStrategy:CurrentUser": "仅当前用户",
"DataAccessStrategy:CurrentRoles": "仅当前用户角色",
"DataAccessStrategy:CurrentOrganizationUnits": "仅当前用户组织机构",
"DataAccessStrategy:CurrentAndSubOrganizationUnits": "仅当前用户组织机构及下级机构"
}
}

3
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/FodyWeavers.xml

@ -1,3 +0,0 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

24
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN.Abp.DataProtection.Application.Contracts.csproj

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.DataProtection.Application.Contracts</AssemblyName>
<PackageId>LINGYUN.Abp.DataProtection.Application.Contracts</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application.Contracts" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.DataProtection.Abstractions\LINGYUN.Abp.DataProtection.Abstractions.csproj" />
</ItemGroup>
</Project>

12
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationContractsModule.cs

@ -1,12 +0,0 @@
using Volo.Abp.Application;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.DataProtection;
[DependsOn(
typeof(AbpDataProtectionAbstractionsModule),
typeof(AbpDddApplicationContractsModule))]
public class AbpDataProtectionApplicationContractsModule : AbpModule
{
}

7
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityEnumInfoDto.cs

@ -1,7 +0,0 @@
namespace LINGYUN.Abp.DataProtection;
public class EntityEnumInfoDto
{
public string Key { get; set; }
public object Value { get; set; }
}

29
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityPropertyInfoDto.cs

@ -1,29 +0,0 @@
namespace LINGYUN.Abp.DataProtection;
public class EntityPropertyInfoDto
{
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 显示名称
/// </summary>
public string DisplayName { get; set; }
/// <summary>
/// 类型全名
/// </summary>
public string TypeFullName { get; set; }
/// <summary>
/// JavaScript类型
/// </summary>
public string JavaScriptType { get; set; }
/// <summary>
/// 枚举列表
/// </summary>
public EntityEnumInfoDto[] Enums { get; set; } = new EntityEnumInfoDto[0];
/// <summary>
/// 允许的过滤操作列表
/// </summary>
public DataAccessFilterOperate[] Operates { get; set; }
}

17
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoDto.cs

@ -1,17 +0,0 @@
namespace LINGYUN.Abp.DataProtection;
public class EntityTypeInfoDto
{
/// <summary>
/// 实体名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 显示名称
/// </summary>
public string DisplayName { get; set; }
/// <summary>
/// 可访问属性列表
/// </summary>
public EntityPropertyInfoDto[] Properties { get; set; } = new EntityPropertyInfoDto[0];
}

6
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoGetInput.cs

@ -1,6 +0,0 @@
namespace LINGYUN.Abp.DataProtection;
public class EntityTypeInfoGetInput
{
public DataAccessOperation Operation { get; set; }
}

14
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/IEntityTypeInfoAppService.cs

@ -1,14 +0,0 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.DataProtection;
public interface IEntityTypeInfoAppService : IApplicationService
{
/// <summary>
/// 获取实体可访问规则
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<EntityTypeInfoDto> GetEntityRuleAsync(EntityTypeInfoGetInput input);
}

3
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/FodyWeavers.xml

@ -1,3 +0,0 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>

25
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN.Abp.DataProtection.Application.csproj

@ -1,25 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\..\configureawait.props" />
<Import Project="..\..\..\..\common.props" />
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net8.0;net9.0</TargetFrameworks>
<AssemblyName>LINGYUN.Abp.DataProtection.Application</AssemblyName>
<PackageId>LINGYUN.Abp.DataProtection.Application</PackageId>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Application" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.DataProtection\LINGYUN.Abp.DataProtection.csproj" />
<ProjectReference Include="..\LINGYUN.Abp.DataProtection.Application.Contracts\LINGYUN.Abp.DataProtection.Application.Contracts.csproj" />
</ItemGroup>
</Project>

13
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationModule.cs

@ -1,13 +0,0 @@
using Volo.Abp.Application;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.DataProtection;
[DependsOn(
typeof(AbpDataProtectionApplicationContractsModule),
typeof(AbpDataProtectionModule),
typeof(AbpDddApplicationModule))]
public class AbpDataProtectionApplicationModule : AbpModule
{
}

47
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/EntityTypeInfoAppService.cs

@ -1,47 +0,0 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Localization;
namespace LINGYUN.Abp.DataProtection;
public abstract class EntityTypeInfoAppService<TEntity> : ApplicationService, IEntityTypeInfoAppService
{
protected IDataAccessEntityTypeInfoProvider EntityTypeInfoProvider => LazyServiceProvider.GetRequiredService<IDataAccessEntityTypeInfoProvider>();
[Authorize]
public virtual async Task<EntityTypeInfoDto> GetEntityRuleAsync(EntityTypeInfoGetInput input)
{
var entityType = typeof(TEntity);
var resourceType = LocalizationResource ?? typeof(DefaultResource);
var context = new DataAccessEntitTypeInfoContext(
entityType,
resourceType,
input.Operation,
LazyServiceProvider);
var model = await EntityTypeInfoProvider.GetEntitTypeInfoAsync(context);
return new EntityTypeInfoDto
{
Name = model.Name,
DisplayName = model.DisplayName,
Properties = model.Properties.Select(prop => new EntityPropertyInfoDto
{
Name = prop.Name,
DisplayName = prop.DisplayName,
TypeFullName = prop.TypeFullName,
JavaScriptType = prop.JavaScriptType,
Operates = prop.Operates,
Enums = prop.Enums.Select(em => new EntityEnumInfoDto
{
Key = em.Key,
Value = em.Value,
}).ToArray()
}).ToArray(),
};
}
}

10
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/System/NullableTypeExtensions.cs

@ -1,10 +0,0 @@
namespace System;
internal static class NullableTypeExtensions
{
public static bool IsNullableType(this Type theType) =>
theType.IsGenericType(typeof(Nullable<>));
public static bool IsGenericType(this Type type, Type genericType) =>
type.IsGenericType && type.GetGenericTypeDefinition() == genericType;
}

20
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWritePropertiesInterceptor.cs

@ -36,18 +36,22 @@ public class AbpDataProtectedWritePropertiesInterceptor : SaveChangesInterceptor
allowProperties.AddIfNotContains(properties);
}
if (DataProtectionOptions.Value.EntityIgnoreProperties.TryGetValue(entityType, out var entityIgnoreProps))
// 仅配置了字段级控制才生效
if (allowProperties.Count != 0)
{
allowProperties.AddIfNotContains(entityIgnoreProps);
}
if (DataProtectionOptions.Value.EntityIgnoreProperties.TryGetValue(entityType, out var entityIgnoreProps))
{
allowProperties.AddIfNotContains(entityIgnoreProps);
}
allowProperties.AddIfNotContains(DataProtectionOptions.Value.GlobalIgnoreProperties);
allowProperties.AddIfNotContains(DataProtectionOptions.Value.GlobalIgnoreProperties);
foreach (var property in entry.Properties)
{
if (!allowProperties.Contains(property.Metadata.Name))
foreach (var property in entry.Properties)
{
property.IsModified = false;
if (!allowProperties.Contains(property.Metadata.Name))
{
property.IsModified = false;
}
}
}
}

16
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs

@ -43,14 +43,14 @@ public abstract class AbpDataProtectionDbContext<TDbContext> : AbpDbContext<TDbC
if (entry.Entity is IDataProtected data)
{
// TODO: 埋点, 以后可用EF.Functions查询
if (data.GetProperty(DataAccessKeywords.AUTH_ROLES) == null)
{
data.SetProperty(DataAccessKeywords.AUTH_ROLES, CurrentUser.Roles.Select(role => $"[{role}]").JoinAsString(","));
}
if (data.GetProperty(DataAccessKeywords.AUTH_ORGS) == null)
{
data.SetProperty(DataAccessKeywords.AUTH_ORGS, CurrentUser.FindOrganizationUnits().Select(ou => $"[{ou}]").JoinAsString(","));
}
//if (data.GetProperty(DataAccessKeywords.AUTH_ROLES) == null)
//{
// data.SetProperty(DataAccessKeywords.AUTH_ROLES, CurrentUser.Roles);
//}
//if (data.GetProperty(DataAccessKeywords.AUTH_ORGS) == null)
//{
// data.SetProperty(DataAccessKeywords.AUTH_ORGS, CurrentUser.FindOrganizationUnits());
//}
}
}
}

54
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContextModelBuilderExtensions.cs

@ -2,15 +2,55 @@
using System;
using Volo.Abp;
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore;
public static class AbpDataProtectionDbContextModelBuilderExtensions
{
public static class AbpDataProtectionDbContextModelBuilderExtensions
public static void ConfigureEntityAuth<TEntity, TKey, TEntityAuth>(this ModelBuilder builder)
where TEntity : class
where TEntityAuth : DataAuthBase<TEntity, TKey>
{
public static void ConfigureLocalization(
this ModelBuilder builder,
Action<AbpDataProtectionModelBuilderConfigurationOptions> optionsAction = null)
Check.NotNull(builder, nameof(builder));
var entityType = builder.Model.FindEntityType(typeof(TEntity)) ??
throw new ArgumentException("In the builder.ConfigureEntityAuth<TEntity> configuration entity mapping relationship before ().");
var entityTableName = entityType.GetTableName() ?? typeof(TEntity).Name;
var entitySchema = entityType.GetSchema();
var keyValueType = typeof(TKey);
builder.Entity<TEntityAuth>(b =>
{
Check.NotNull(builder, nameof(builder));
}
b.ToTable(entityTableName + "Auths", entitySchema);
b.Property(p => p.EntityType)
.HasColumnName(nameof(DataAuthBase<TEntity, TKey>.EntityType))
.HasMaxLength(128)
.IsRequired();
if (keyValueType == typeof(string) || keyValueType == typeof(Guid))
{
b.Property(p => p.EntityId)
.HasColumnName(nameof(DataAuthBase<TEntity, TKey>.EntityId))
.HasMaxLength(64)
.IsRequired();
}
else
{
b.Property(p => p.EntityId)
.HasColumnName(nameof(DataAuthBase<TEntity, TKey>.EntityId))
.IsRequired();
}
b.Property(p => p.Role)
.HasColumnName(nameof(DataAuthBase<TEntity, TKey>.Role))
.HasMaxLength(32);
b.Property(p => p.OrganizationUnit)
.HasColumnName(nameof(DataAuthBase<TEntity, TKey>.OrganizationUnit))
.HasMaxLength(20);
b.HasIndex(p => p.Role);
b.HasIndex(p => p.OrganizationUnit);
});
}
}

7
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionEntityFrameworkCoreModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore;
@ -8,4 +9,8 @@ namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore;
typeof(AbpEntityFrameworkCoreModule))]
public class AbpDataProtectionEntityFrameworkCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.TryAddTransient<IDataAccessStrategyFilterBuilder, EfCoreDataAccessStrategyFilterBuilder>();
}
}

172
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataAccessStrategyFilterBuilder.cs

@ -0,0 +1,172 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Users;
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore;
public class EfCoreDataAccessStrategyFilterBuilder : DataAccessStrategyFilterBuilderBase
{
private readonly ICurrentUser _currentUser;
private static readonly MethodInfo LikeMethodInfo
= typeof(DbFunctionsExtensions)
.GetMethod(
nameof(DbFunctionsExtensions.Like),
new[] { typeof(DbFunctions), typeof(string), typeof(string) });
private static readonly MethodInfo ContainsMethodInfo
= typeof(Enumerable)
.GetMethods()
.First(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2)
.MakeGenericMethod(typeof(string));
public EfCoreDataAccessStrategyFilterBuilder(
ICurrentUser currentUser,
IDataFilter dataFilter,
IDataAccessScope dataAccessScope,
IDataAccessStrategyStateProvider strategyStateProvider)
: base(dataFilter, dataAccessScope, strategyStateProvider)
{
_currentUser = currentUser;
}
protected override IQueryable<TEntity> Build<TEntity, TKey, TEntityAuth>(IQueryable<TEntity> entity, IQueryable<TEntityAuth> entityAuth, DataAccessStrategyState state)
{
var parameterEntity = Expression.Parameter(typeof(TEntity), "e");
var parameterEntityAuth = Expression.Parameter(typeof(TEntityAuth), "ea");
var entityIdProperty = Expression.Property(parameterEntity, nameof(IEntity<TKey>.Id));
var entityIdAuthProperty = Expression.Property(parameterEntityAuth, nameof(DataAuthBase<TEntity, TKey>.EntityId));
// e.Id = ea.EntityId
var entityIdMatch = Expression.Equal(entityIdAuthProperty, entityIdProperty);
switch (state.Strategy)
{
case DataAccessStrategy.CurrentUser:
var creatorIdProperty = Expression.Property(parameterEntity, nameof(IDataProtected.CreatorId));
var creatorId = Expression.Constant(_currentUser.Id, typeof(Guid?));
var currentUserExp = Expression.Equal(creatorIdProperty, creatorId);
// e => e.CreatorId = _currentUser.Id
var currentUserFunc = Expression.Lambda<Func<TEntity, bool>>(currentUserExp, parameterEntity);
return entity.Where(currentUserFunc);
case DataAccessStrategy.CurrentRoles:
var roleProperty = Expression.Property(
parameterEntityAuth,
nameof(DataAuthBase<TEntity, TKey>.Role)
);
var roleContains = Expression.Call(
ContainsMethodInfo,
Expression.Constant(_currentUser.Roles),
roleProperty
);
// and ea.Role in ("Users") and e.Id = ea.EntityId
var roleFinalCondition = Expression.AndAlso(roleContains, entityIdMatch);
var existsSubQueryWithRole = Expression.Call(
typeof(Queryable),
"Any",
new Type[] { typeof(TEntityAuth) },
entityAuth.Expression,
Expression.Lambda<Func<TEntityAuth, bool>>(roleFinalCondition, parameterEntityAuth)
);
var whereExistsCondition = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { typeof(TEntity) },
entity.Expression,
Expression.Lambda<Func<TEntity, bool>>(
existsSubQueryWithRole, parameterEntity
)
);
return entity.Provider.CreateQuery<TEntity>(whereExistsCondition);
case DataAccessStrategy.CurrentOrganizationUnits:
var equalOrganizationUnits = _currentUser.FindOrganizationUnits();
var ouProperty = Expression.Property(
parameterEntityAuth,
nameof(DataAuthBase<TEntity, TKey>.OrganizationUnit)
);
var ouContains = Expression.Call(
ContainsMethodInfo,
Expression.Constant(equalOrganizationUnits),
ouProperty
);
// and ea.OrganizationUnit in ("00001.00001") and e.Id = ea.EntityId
var finalCondition = Expression.AndAlso(ouContains, entityIdMatch);
var existsSubQueryWithOu = Expression.Call(
typeof(Queryable),
"Any",
new Type[] { typeof(TEntityAuth) },
entityAuth.Expression,
Expression.Lambda<Func<TEntityAuth, bool>>(finalCondition, parameterEntityAuth)
);
var whereExistsConditionWithOu = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { typeof(TEntity) },
entity.Expression,
Expression.Lambda<Func<TEntity, bool>>(
existsSubQueryWithOu, parameterEntity
)
);
return entity.Provider.CreateQuery<TEntity>(whereExistsConditionWithOu);
case DataAccessStrategy.CurrentAndSubOrganizationUnits:
var startsWithOrganizationUnits = _currentUser.FindOrganizationUnits();
var dbFunctions = Expression.Property(null, typeof(EF), nameof(EF.Functions));
var filteredEntityAuth = startsWithOrganizationUnits
.Select(ouCode =>
(Expression)Expression.Call(
typeof(Queryable),
"Any",
new Type[] { typeof(TEntityAuth) },
entityAuth.Expression,
Expression.Lambda<Func<TEntityAuth, bool>>(
Expression.AndAlso(
Expression.Equal(
Expression.Property(parameterEntityAuth, nameof(DataAuthBase<TEntity, TKey>.EntityId)),
Expression.Property(parameterEntity, nameof(IEntity<TKey>.Id))
),
Expression.Call(
LikeMethodInfo,
dbFunctions,
Expression.Property(parameterEntityAuth, nameof(DataAuthBase<TEntity, TKey>.OrganizationUnit)),
Expression.Constant(ouCode + "%")
)
),
parameterEntityAuth
)
)
)
.Aggregate(Expression.OrElse);
var startsWithWhereExistsConditionWithOu = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { typeof(TEntity) },
entity.Expression,
Expression.Lambda<Func<TEntity, bool>>(filteredEntityAuth, parameterEntity)
);
return entity.Provider.CreateQuery<TEntity>(startsWithWhereExistsConditionWithOu);
}
return entity;
}
}

163
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepository.cs

@ -1,28 +1,36 @@
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Users;
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore;
public abstract class EfCoreDataProtectionRepository<TDbContext, TEntity, TKey> :
public abstract class EfCoreDataProtectionRepository<TDbContext, TEntity, TKey, TEntityAuth> :
EfCoreRepository<TDbContext, TEntity, TKey>,
IDataProtectionRepository<TEntity>
where TDbContext : IEfCoreDbContext
where TEntity : class, IEntity<TKey>
where TEntity : class, IEntity<TKey>, IDataProtected
where TEntityAuth : DataAuthBase<TEntity, TKey>
{
private readonly IDataAuthorizationService _dataAuthorizationService;
private readonly IEntityTypeFilterBuilder _entityTypeFilterBuilder;
private readonly IEntityPropertyResultBuilder _entityPropertyResultBuilder;
protected ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
protected IDataAccessStrategyFilterBuilder StrategyFilterBuilder => LazyServiceProvider.GetService<IDataAccessStrategyFilterBuilder>();
protected EfCoreDataProtectionRepository(
[NotNull] IDbContextProvider<TDbContext> dbContextProvider,
[NotNull] IDataAuthorizationService dataAuthorizationService,
@ -37,12 +45,27 @@ public abstract class EfCoreDataProtectionRepository<TDbContext, TEntity, TKey>
public async override Task<IQueryable<TEntity>> GetQueryableAsync()
{
var queryable = await base.GetQueryableAsync();
var dataAccessFilterExp = await _entityTypeFilterBuilder.Build<TEntity>(DataAccessOperation.Read);
var dbContext = await GetDbContextAsync();
var dbSet = dbContext.Set<TEntity>();
var queryable = dbSet.AsQueryable().AsNoTrackingIf(!ShouldTrackingEntityChange());
var strategyFilterResult = await StrategyFilterBuilder?.Build<TEntity, TKey, TEntityAuth>(queryable, dbContext.Set<TEntityAuth>());
if (strategyFilterResult != null && strategyFilterResult.Strategy != DataAccessStrategy.Custom)
{
// 根据配置的用户数据权限策略进行过滤
queryable = strategyFilterResult.Queryable;
}
else
{
// 根据配置的用户实体数据权限规则过滤
var dataAccessFilterExp = await _entityTypeFilterBuilder.Build<TEntity>(DataAccessOperation.Read);
queryable = queryable.Where(dataAccessFilterExp);
}
// 仅查询授权字段
var accessFieldExp = await _entityPropertyResultBuilder.Build<TEntity>(DataAccessOperation.Read);
queryable = queryable.Where(dataAccessFilterExp).Select(accessFieldExp);
queryable = queryable.Select(accessFieldExp);
return queryable;
}
@ -73,6 +96,62 @@ public abstract class EfCoreDataProtectionRepository<TDbContext, TEntity, TKey>
await base.DeleteManyAsync(entities, autoSave, cancellationToken);
}
public async override Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
{
CheckAndSetId(entity);
var dbContext = await GetDbContextAsync();
var savedEntity = (await dbContext.Set<TEntity>().AddAsync(entity, GetCancellationToken(cancellationToken))).Entity;
await PersistenEntityAuthInfoAsync(dbContext, savedEntity, GetCancellationToken(cancellationToken));
if (autoSave)
{
await dbContext.SaveChangesAsync(GetCancellationToken(cancellationToken));
}
return savedEntity;
}
public async override Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false, CancellationToken cancellationToken = default)
{
var entityArray = entities.ToArray();
if (entityArray.IsNullOrEmpty())
{
return;
}
var dbContext = await GetDbContextAsync();
cancellationToken = GetCancellationToken(cancellationToken);
foreach (var entity in entityArray)
{
CheckAndSetId(entity);
}
await PersistenEntityAuthInfoAsync(dbContext, entityArray, cancellationToken);
if (BulkOperationProvider != null)
{
await BulkOperationProvider.InsertManyAsync<TDbContext, TEntity>(
this,
entityArray,
autoSave,
GetCancellationToken(cancellationToken)
);
return;
}
await dbContext.Set<TEntity>().AddRangeAsync(entityArray, cancellationToken);
if (autoSave)
{
await dbContext.SaveChangesAsync(cancellationToken);
}
}
public async override Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false,
CancellationToken cancellationToken = default)
{
@ -88,6 +167,78 @@ public abstract class EfCoreDataProtectionRepository<TDbContext, TEntity, TKey>
await base.UpdateManyAsync(entities, autoSave, cancellationToken);
}
/// <summary>
/// 创建实体角色数据权限实体
/// </summary>
/// <param name="entity"></param>
/// <param name="role"></param>
/// <returns></returns>
protected virtual TEntityAuth CreateEntityRoleAuth(TEntity entity, string role)
{
var entityAuth = Activator.CreateInstance(typeof(TEntityAuth),
new object[] { entity.Id, role, null, CurrentTenant.Id });
return entityAuth as TEntityAuth;
}
/// <summary>
/// 创建实体组织机构数据权限实体
/// </summary>
/// <param name="entity"></param>
/// <param name="ouCode"></param>
/// <returns></returns>
protected virtual TEntityAuth CreateEntityOrganizationUnitAuth(TEntity entity, string ouCode)
{
var entityAuth = Activator.CreateInstance(typeof(TEntityAuth),
new object[] { entity.Id, null, ouCode, CurrentTenant.Id });
return entityAuth as TEntityAuth;
}
/// <summary>
/// 持久化实体数据权限
/// </summary>
/// <param name="dbContext"></param>
/// <param name="entity"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected async virtual Task PersistenEntityAuthInfoAsync(TDbContext dbContext, TEntity entity, CancellationToken cancellationToken = default)
{
// 可重写此方法以进行分布式持久化数据权限
var entityAuth = dbContext.Set<TEntityAuth>();
var entityRoleAuths = CurrentUser.Roles
.Select((role) => CreateEntityRoleAuth(entity, role));
var entityOuAuths = CurrentUser.FindOrganizationUnits()
.Select((ouCode) => CreateEntityOrganizationUnitAuth(entity, ouCode));
await entityAuth.AddRangeAsync(entityRoleAuths.Union(entityOuAuths), GetCancellationToken(cancellationToken));
}
/// <summary>
/// 持久化实体数据权限
/// </summary>
/// <param name="dbContext"></param>
/// <param name="entities"></param>
/// <param name="cancellationToken"></param>
/// <returns></returns>
protected async virtual Task PersistenEntityAuthInfoAsync(TDbContext dbContext, IEnumerable<TEntity> entities, CancellationToken cancellationToken = default)
{
// 可重写此方法以进行分布式持久化数据权限
var entityAuth = dbContext.Set<TEntityAuth>();
var entityAuths = new List<TEntityAuth>();
foreach (var entity in entities)
{
var entityRoleAuths = CurrentUser.Roles
.Select((role) => CreateEntityRoleAuth(entity, role));
var entityOuAuths = CurrentUser.FindOrganizationUnits()
.Select((ouCode) => CreateEntityOrganizationUnitAuth(entity, ouCode));
entityAuths.AddRange(entityRoleAuths.Union(entityOuAuths));
}
await entityAuth.AddRangeAsync(entityAuths, GetCancellationToken(cancellationToken));
}
}
public abstract class EfCoreDataProtectionRepository<TDbContext, TEntity> : EfCoreRepository<TDbContext, TEntity>

6
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs

@ -23,6 +23,7 @@ public class AbpDataProtectionModule : AbpModule
{
Configure<AbpDataProtectionOptions>(options =>
{
// 当前用户数据过滤
options.KeywordContributors.Add(DataAccessCurrentUserContributor.Name, new DataAccessCurrentUserContributor());
options.OperateContributors.Add(DataAccessFilterOperate.Equal, new DataAccessEqualContributor());
@ -36,10 +37,13 @@ public class AbpDataProtectionModule : AbpModule
options.OperateContributors.Add(DataAccessFilterOperate.Contains, new DataAccessContainsContributor());
options.OperateContributors.Add(DataAccessFilterOperate.NotContains, new DataAccessNotContainsContributor());
options.SubjectContributors.Add(new DataAccessUserIdContributor());
options.SubjectContributors.Add(new DataAccessClientIdContributor());
options.SubjectContributors.Add(new DataAccessUserIdContributor());
options.SubjectContributors.Add(new DataAccessRoleNameContributor());
options.SubjectContributors.Add(new DataAccessOrganizationUnitContributor());
// 权限策略提供程序
options.StrategyContributors.Add(new DataAccessStrategyRoleNameContributor());
});
Configure<AbpExceptionLocalizationOptions>(options =>

5
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionOptions.cs

@ -15,6 +15,10 @@ public class AbpDataProtectionOptions
/// </summary>
public bool IsEnabled { get; set; }
/// <summary>
/// 数据权限策略
/// </summary>
public IList<IDataAccessStrategyContributor> StrategyContributors { get; }
/// <summary>
/// 权限主体
/// </summary>
public IList<IDataAccessSubjectContributor> SubjectContributors { get; }
@ -46,6 +50,7 @@ public class AbpDataProtectionOptions
{
IsEnabled = true;
SubjectContributors = new List<IDataAccessSubjectContributor>();
StrategyContributors = new List<IDataAccessStrategyContributor>();
KeywordContributors = new Dictionary<string, IDataAccessKeywordContributor>();
OperateContributors = new Dictionary<DataAccessFilterOperate, IDataAccessOperateContributor>();
DefaultEntityFilters = new Dictionary<Type, Func<IServiceProvider, Type, DataAccessOperation, LambdaExpression>>();

7
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessKeywordContributorContext.cs

@ -1,15 +1,16 @@
using System;
using System.Linq.Expressions;
namespace LINGYUN.Abp.DataProtection;
public class DataAccessKeywordContributorContext
{
public IServiceProvider ServiceProvider { get; }
public Type ConversionType { get; }
public LambdaExpression Expression { get; }
public DataAccessKeywordContributorContext(
IServiceProvider serviceProvider,
Type conversionType)
LambdaExpression expression)
{
ServiceProvider = serviceProvider;
ConversionType = conversionType;
Expression = expression;
}
}

25
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessResourceCacheInvalidator.cs

@ -1,4 +1,5 @@
using System.Threading.Tasks;
using LINGYUN.Abp.DataProtection.Stores;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
@ -7,12 +8,30 @@ namespace LINGYUN.Abp.DataProtection;
public class DataAccessResourceCacheInvalidator : IDistributedEventHandler<DataAccessResourceChangeEvent>, ITransientDependency
{
private readonly IDataProtectedResourceStore _resourceStore;
public DataAccessResourceCacheInvalidator(IDataProtectedResourceStore resourceStore)
private readonly IDataProtectedStrategyStateStore _strategyStateStore;
public DataAccessResourceCacheInvalidator(
IDataProtectedResourceStore resourceStore,
IDataProtectedStrategyStateStore strategyStateStore)
{
_resourceStore = resourceStore;
_strategyStateStore = strategyStateStore;
}
public async virtual Task HandleEventAsync(DataAccessResourceChangeEvent eventData)
{
await _resourceStore.SetAsync(eventData.Resource);
if (eventData.IsEnabled)
{
await _resourceStore.SetAsync(eventData.Resource);
// 角色权限策略变更为自定义规则
await _strategyStateStore.SetAsync(
new DataAccessStrategyState(
eventData.Resource.SubjectName,
new string[] { eventData.Resource.SubjectId },
DataAccessStrategy.Custom));
}
else
{
await _resourceStore.RemoveAsync(eventData.Resource);
}
}
}

12
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyContributorContext.cs

@ -0,0 +1,12 @@
using System;
namespace LINGYUN.Abp.DataProtection;
public class DataAccessStrategyContributorContext
{
public IServiceProvider ServiceProvider { get; }
public DataAccessStrategyContributorContext(IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
}
}

16
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyFilterBuildResult.cs

@ -0,0 +1,16 @@
using System.Linq;
namespace LINGYUN.Abp.DataProtection;
public class DataAccessStrategyFilterBuildResult<TEntity>
{
public DataAccessStrategy Strategy { get; }
public IQueryable<TEntity> Queryable { get; }
public DataAccessStrategyFilterBuildResult(
DataAccessStrategy strategy,
IQueryable<TEntity> queryable)
{
Strategy = strategy;
Queryable = queryable;
}
}

66
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyFilterBuilderBase.cs

@ -0,0 +1,66 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Data;
namespace LINGYUN.Abp.DataProtection;
public abstract class DataAccessStrategyFilterBuilderBase : IDataAccessStrategyFilterBuilder
{
private readonly IDataFilter _dataFilter;
private readonly IDataAccessScope _dataAccessScope;
private readonly IDataAccessStrategyStateProvider _strategyStateProvider;
protected DataAccessStrategyFilterBuilderBase(
IDataFilter dataFilter,
IDataAccessScope dataAccessScope,
IDataAccessStrategyStateProvider strategyStateProvider)
{
_dataFilter = dataFilter;
_dataAccessScope = dataAccessScope;
_strategyStateProvider = strategyStateProvider;
}
public async virtual Task<DataAccessStrategyFilterBuildResult<TEntity>> Build<TEntity, TKey, TEntityAuth>(IQueryable<TEntity> entity, IQueryable<TEntityAuth> entityAuth)
where TEntityAuth : DataAuthBase<TEntity, TKey>
{
if (ShouldApplyFilter(typeof(TEntity), DataAccessOperation.Read))
{
var strategyState = await _strategyStateProvider.GetOrNullAsync();
if (strategyState != null && strategyState.Strategy != DataAccessStrategy.Custom)
{
var newQueryable = Build<TEntity, TKey, TEntityAuth>(entity, entityAuth, strategyState);
return new DataAccessStrategyFilterBuildResult<TEntity>(
strategyState.Strategy,
newQueryable);
}
}
return null;
}
protected virtual bool ShouldApplyFilter(Type entityType, DataAccessOperation operation)
{
// TODO: 使用一个范围标志来确定当前需要禁用的数据权限操作
if (!_dataFilter.IsEnabled<IDataProtected>())
{
return false;
}
if (entityType.IsDefined(typeof(DisableDataProtectedAttribute), true))
{
return false;
}
if (_dataAccessScope.Operations != null && !_dataAccessScope.Operations.Contains(operation))
{
return false;
}
return true;
}
protected abstract IQueryable<TEntity> Build<TEntity, TKey, TEntityAuth>(IQueryable<TEntity> entity, IQueryable<TEntityAuth> entityAuth, DataAccessStrategyState state)
where TEntityAuth : DataAuthBase<TEntity, TKey>;
}

36
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyStateProvider.cs

@ -0,0 +1,36 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.DataProtection;
public class DataAccessStrategyStateProvider : IDataAccessStrategyStateProvider, ITransientDependency
{
private readonly AbpDataProtectionOptions _options;
private readonly IServiceScopeFactory _serviceScopeFactory;
public DataAccessStrategyStateProvider(
IOptions<AbpDataProtectionOptions> options,
IServiceScopeFactory serviceScopeFactory)
{
_options = options.Value;
_serviceScopeFactory = serviceScopeFactory;
}
public async virtual Task<DataAccessStrategyState> GetOrNullAsync()
{
using var scope = _serviceScopeFactory.CreateScope();
var context = new DataAccessStrategyContributorContext(scope.ServiceProvider);
foreach (var contributor in _options.StrategyContributors)
{
var strategyState = await contributor.GetOrNullAsync(context);
if (strategyState != null)
{
return strategyState;
}
}
return null;
}
}

33
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAuthBase.cs

@ -0,0 +1,33 @@
using System;
using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.DataProtection;
public abstract class DataAuthBase<TEntity, TKey> : Entity<long>, IMultiTenant
{
public virtual Guid? TenantId { get; protected set; }
public virtual TKey EntityId { get; protected set; }
public virtual TEntity Entity { get; protected set; }
public virtual string EntityType { get; protected set; }
public virtual string Role { get; protected set; }
public virtual string OrganizationUnit { get; protected set; }
protected DataAuthBase()
{
}
protected DataAuthBase(
TKey entityId,
string role,
string organizationUnit,
Guid? tenantId = null)
{
TenantId = tenantId;
EntityId = entityId;
Role = role;
OrganizationUnit = organizationUnit;
EntityType = typeof(TEntity).FullName;
}
}

22
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptor.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.Options;
using System.Reflection;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
@ -8,12 +9,17 @@ namespace LINGYUN.Abp.DataProtection;
public class DataProtectedInterceptor : AbpInterceptor, ITransientDependency
{
private readonly IDataFilter _dataFilter;
private readonly IDataAccessScope _dataAccessScope;
private readonly AbpDataProtectionOptions _options;
public DataProtectedInterceptor(IDataFilter dataFilter, IOptions<AbpDataProtectionOptions> options)
public DataProtectedInterceptor(
IDataFilter dataFilter,
IDataAccessScope dataAccessScope,
IOptions<AbpDataProtectionOptions> options)
{
_dataFilter = dataFilter;
_options = options.Value;
_dataAccessScope = dataAccessScope;
}
public async override Task InterceptAsync(IAbpMethodInvocation invocation)
@ -23,9 +29,20 @@ public class DataProtectedInterceptor : AbpInterceptor, ITransientDependency
using (_dataFilter.Disable<IDataProtected>())
{
await invocation.ProceedAsync();
return;
}
return;
}
var dataProtected = invocation.Method.GetCustomAttribute<DataProtectedAttribute>();
if (dataProtected?.Operations != null)
{
using (_dataAccessScope.BeginScope(dataProtected.Operations))
{
await invocation.ProceedAsync();
}
return;
}
await invocation.ProceedAsync();
}
@ -38,7 +55,6 @@ public class DataProtectedInterceptor : AbpInterceptor, ITransientDependency
return true;
}
// TODO: 使用一个范围标志来确定当前需要禁用的数据权限操作
if (invocation.Method.IsDefined(typeof(DisableDataProtectedAttribute), true))
{
return true;

16
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityPropertyResultBuilder.cs

@ -3,7 +3,6 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
@ -12,16 +11,19 @@ namespace LINGYUN.Abp.DataProtection;
public class EntityPropertyResultBuilder : IEntityPropertyResultBuilder, ITransientDependency
{
private readonly IDataFilter _dataFilter;
private readonly IDataAccessScope _dataAccessScope;
private readonly IServiceProvider _serviceProvider;
private readonly AbpDataProtectionOptions _options;
public EntityPropertyResultBuilder(
IDataFilter dataFilter,
IDataAccessScope dataAccessScope,
IServiceProvider serviceProvider,
IOptions<AbpDataProtectionOptions> options)
{
_options = options.Value;
_dataFilter = dataFilter;
_dataAccessScope = dataAccessScope;
_serviceProvider = serviceProvider;
}
@ -131,20 +133,12 @@ public class EntityPropertyResultBuilder : IEntityPropertyResultBuilder, ITransi
return false;
}
var disableAttr = entityType.GetCustomAttribute<DisableDataProtectedAttribute>();
if (disableAttr != null)
if (entityType.IsDefined(typeof(DisableDataProtectedAttribute), true))
{
if (disableAttr.Operation.HasValue && disableAttr.Operation != operation)
{
return true;
}
return false;
}
var dataProtected = entityType.GetCustomAttribute<DataProtectedAttribute>();
if (dataProtected != null && dataProtected.Operation != operation)
if (_dataAccessScope.Operations != null && !_dataAccessScope.Operations.Contains(operation))
{
return false;
}

34
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityTypeFilterBuilder.cs

@ -17,16 +17,19 @@ namespace LINGYUN.Abp.DataProtection;
public class EntityTypeFilterBuilder : IEntityTypeFilterBuilder, ITransientDependency
{
private readonly IDataFilter _dataFilter;
private readonly IDataAccessScope _dataAccessScope;
private readonly IServiceProvider _serviceProvider;
private readonly AbpDataProtectionOptions _options;
public EntityTypeFilterBuilder(
IDataFilter dataFilter,
IDataAccessScope dataAccessScope,
IServiceProvider serviceProvider,
IOptions<AbpDataProtectionOptions> options)
{
_options = options.Value;
_dataFilter = dataFilter;
_dataAccessScope = dataAccessScope;
_serviceProvider = serviceProvider;
}
@ -195,10 +198,6 @@ public class EntityTypeFilterBuilder : IEntityTypeFilterBuilder, ITransientDepen
private Expression GetExpressionBody(ParameterExpression param, DataAccessFilterRule rule)
{
if (!_options.OperateContributors.TryGetValue(rule.Operate, out var contributor))
{
throw new InvalidOperationException($"Invalid data permission operator {rule.Operate}");
}
if (rule == null)
{
return Expression.Constant(true);
@ -208,9 +207,15 @@ public class EntityTypeFilterBuilder : IEntityTypeFilterBuilder, ITransientDepen
{
return Expression.Constant(true);
}
var constant = ChangeTypeToExpression(rule, expression.Body.Type);
return rule.IsLeft ? contributor.BuildExpression(constant, expression.Body) : contributor.BuildExpression(expression.Body, constant);
if (!_options.OperateContributors.TryGetValue(rule.Operate, out var operateContributor))
{
throw new InvalidOperationException($"Invalid data permission operator {rule.Operate}");
}
var constant = ChangeTypeToExpression(rule, expression);
return rule.IsLeft ? operateContributor.BuildExpression(constant, expression.Body) : operateContributor.BuildExpression(expression.Body, constant);
}
private static LambdaExpression GetPropertyLambdaExpression(ParameterExpression param, DataAccessFilterRule rule)
@ -243,11 +248,12 @@ public class EntityTypeFilterBuilder : IEntityTypeFilterBuilder, ITransientDepen
return Expression.Lambda(propertyAccess, param);
}
private Expression ChangeTypeToExpression(DataAccessFilterRule rule, Type conversionType)
private Expression ChangeTypeToExpression(DataAccessFilterRule rule, LambdaExpression expression)
{
var conversionType = expression.Body.Type;
if (_options.KeywordContributors.TryGetValue(rule.Value?.ToString() ?? "", out var contributor))
{
var context = new DataAccessKeywordContributorContext(_serviceProvider, conversionType);
var context = new DataAccessKeywordContributorContext(_serviceProvider, expression);
return contributor.Contribute(context);
}
else
@ -290,20 +296,12 @@ public class EntityTypeFilterBuilder : IEntityTypeFilterBuilder, ITransientDepen
return false;
}
var disableAttr = entityType.GetCustomAttribute<DisableDataProtectedAttribute>();
if (disableAttr != null)
if (entityType.IsDefined(typeof(DisableDataProtectedAttribute), true))
{
if (disableAttr.Operation.HasValue && disableAttr.Operation != operation)
{
return true;
}
return false;
}
var dataProtected = entityType.GetCustomAttribute<DataProtectedAttribute>();
if (dataProtected != null && dataProtected.Operation != operation)
if (_dataAccessScope.Operations != null && !_dataAccessScope.Operations.Contains(operation))
{
return false;
}

3
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessKeywordContributor.cs

@ -3,6 +3,9 @@
namespace LINGYUN.Abp.DataProtection;
public interface IDataAccessKeywordContributor
{
bool IsExternal { get; }
string Keyword { get; }
Expression Contribute(DataAccessKeywordContributorContext context);
}

9
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyContributor.cs

@ -0,0 +1,9 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.DataProtection;
public interface IDataAccessStrategyContributor
{
string Name { get; }
Task<DataAccessStrategyState> GetOrNullAsync(DataAccessStrategyContributorContext context);
}

13
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyFilterBuilder.cs

@ -0,0 +1,13 @@
using System.Linq;
using System.Threading.Tasks;
namespace LINGYUN.Abp.DataProtection;
/// <summary>
/// 数据权限策略过滤器
/// </summary>
public interface IDataAccessStrategyFilterBuilder
{
Task<DataAccessStrategyFilterBuildResult<TEntity>> Build<TEntity, TKey, TEntityAuth>(IQueryable<TEntity> entity, IQueryable<TEntityAuth> entityAuth)
where TEntityAuth : DataAuthBase<TEntity, TKey>;
}

8
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyStateProvider.cs

@ -0,0 +1,8 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.DataProtection;
public interface IDataAccessStrategyStateProvider
{
Task<DataAccessStrategyState> GetOrNullAsync();
}

57
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/InMemoryDataProtectedResourceStore.cs

@ -1,57 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.DataProtection;
[Dependency(ServiceLifetime.Singleton, TryRegister = true)]
public class InMemoryDataProtectedResourceStore : IDataProtectedResourceStore
{
private readonly static ConcurrentDictionary<string, DataAccessResource> _cache = new ConcurrentDictionary<string, DataAccessResource>();
public DataAccessResource Get(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation)
{
var key = NormalizeKey(subjectName, subjectId, entityTypeFullName, operation);
if (_cache.TryGetValue(key, out var resource))
{
return resource;
}
return null;
}
public void Remove(DataAccessResource resource)
{
var key = NormalizeKey(resource.SubjectName, resource.SubjectId, resource.EntityTypeFullName, resource.Operation);
_cache.TryRemove(key, out var _);
}
public void Set(DataAccessResource resource)
{
var key = NormalizeKey(resource.SubjectName, resource.SubjectId, resource.EntityTypeFullName, resource.Operation);
_cache.TryAdd(key, resource);
}
private static string NormalizeKey(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation)
{
return $"{subjectName}_{subjectId}_{entityTypeFullName}_{operation}";
}
public Task SetAsync(DataAccessResource resource)
{
Set(resource);
return Task.CompletedTask;
}
public Task RemoveAsync(DataAccessResource resource)
{
Remove(resource);
return Task.CompletedTask;
}
public Task<DataAccessResource> GetAsync(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation)
{
return Task.FromResult(Get(subjectName, subjectId, entityTypeFullName, operation));
}
}

9
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Keywords/DataAccessCurrentUserContributor.cs

@ -6,19 +6,24 @@ using System.Linq.Expressions;
using Volo.Abp.Users;
namespace LINGYUN.Abp.DataProtection.Keywords;
/// <summary>
/// 适用于过滤当前用户数据
/// </summary>
public class DataAccessCurrentUserContributor : IDataAccessKeywordContributor
{
public const string Name = "@CurrentUser";
public string Keyword => Name;
public bool IsExternal => false;
public Expression Contribute(DataAccessKeywordContributorContext context)
{
var conversionType = context.Expression.Body.Type;
var currentUser = context.ServiceProvider.GetRequiredService<ICurrentUser>();
var userId = CastTo(currentUser.Id, context.ConversionType);
var userId = CastTo(currentUser.Id, conversionType);
// entity.Where(x => x.CreatorId == CurrentUser.Id);
return Expression.Constant(userId, context.ConversionType);
return Expression.Constant(userId, conversionType);
}
private static object CastTo(object value, Type conversionType)

44
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataAccessStrategyStateCacheItem.cs

@ -0,0 +1,44 @@
using System;
using Volo.Abp.Caching;
namespace LINGYUN.Abp.DataProtection.Stores;
[Serializable]
[CacheName("AbpDataProtectionStrategyStates")]
public class DataAccessStrategyStateCacheItem
{
private const string CacheKeyFormat = "sn:{0};si:{1}";
/// <summary>
/// 权限主体
/// </summary>
public string SubjectName { get; set; }
/// <summary>
/// 权限主体标识
/// </summary>
public string SubjectId { get; set; }
/// <summary>
/// 权限策略
/// </summary>
public DataAccessStrategy Strategy { get; set; }
public DataAccessStrategyStateCacheItem()
{
}
public DataAccessStrategyStateCacheItem(
string subjectName,
string subjectId,
DataAccessStrategy strategy)
{
SubjectName = subjectName;
SubjectId = subjectId;
Strategy = strategy;
}
public static string CalculateCacheKey(string subjectName, string subjectId)
{
return string.Format(CacheKeyFormat, subjectName, subjectId);
}
}

5
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCache.cs → aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceCache.cs

@ -1,10 +1,9 @@
using LINGYUN.Abp.DataProtection;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Distributed;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.DataProtectionManagement;
namespace LINGYUN.Abp.DataProtection.Stores;
public class DataProtectedResourceCache : IDataProtectedResourceCache, ITransientDependency
{
private readonly IDistributedCache<DataProtectedResourceCacheItem> _cache;

7
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItem.cs → aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceCacheItem.cs

@ -1,10 +1,11 @@
using LINGYUN.Abp.DataProtection;
using System;
using System;
using System.Collections.Generic;
using Volo.Abp.Caching;
namespace LINGYUN.Abp.DataProtectionManagement;
namespace LINGYUN.Abp.DataProtection.Stores;
[Serializable]
[CacheName("AbpDataProtectionResources")]
public class DataProtectedResourceCacheItem
{
private const string CacheKeyFormat = "sn:{0};si:{1},e:{2},o:{3}";

12
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheStore.cs → aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceStore.cs

@ -1,17 +1,13 @@
using LINGYUN.Abp.DataProtection;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.Tasks;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.DataProtectionManagement;
namespace LINGYUN.Abp.DataProtection.Stores;
[Dependency(ServiceLifetime.Transient, ReplaceServices = true)]
[ExposeServices(typeof(IDataProtectedResourceStore), typeof(DataProtectedResourceCacheStore))]
public class DataProtectedResourceCacheStore : IDataProtectedResourceStore, ITransientDependency
public class DataProtectedResourceStore : IDataProtectedResourceStore, ITransientDependency
{
private readonly IDataProtectedResourceCache _cache;
public DataProtectedResourceCacheStore(IDataProtectedResourceCache cache)
public DataProtectedResourceStore(IDataProtectedResourceCache cache)
{
_cache = cache;
}

42
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedStrategyStateCache.cs

@ -0,0 +1,42 @@
using Microsoft.Extensions.Caching.Distributed;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.DataProtection.Stores;
public class DataProtectedStrategyStateCache : IDataProtectedStrategyStateCache, ITransientDependency
{
private readonly IDistributedCache<DataAccessStrategyStateCacheItem> _cache;
public DataProtectedStrategyStateCache(IDistributedCache<DataAccessStrategyStateCacheItem> cache)
{
_cache = cache;
}
public async virtual Task<DataAccessStrategyStateCacheItem> GetAsync(string subjectName, string subjectId)
{
var cacheKey = DataAccessStrategyStateCacheItem.CalculateCacheKey(subjectName, subjectId);
var cacheItem = await _cache.GetAsync(cacheKey);
return cacheItem;
}
public async virtual Task RemoveAsync(DataAccessStrategyState state)
{
foreach (var subjectKey in state.SubjectKeys)
{
var cacheKey = DataAccessStrategyStateCacheItem.CalculateCacheKey(state.SubjectName, subjectKey);
await _cache.RemoveAsync(cacheKey);
}
}
public async virtual Task SetAsync(DataAccessStrategyState state)
{
foreach (var subjectKey in state.SubjectKeys)
{
var cacheKey = DataAccessStrategyStateCacheItem.CalculateCacheKey(state.SubjectName, subjectKey);
var cacheItem = new DataAccessStrategyStateCacheItem(state.SubjectName, subjectKey, state.Strategy);
await _cache.SetAsync(cacheKey, cacheItem, new DistributedCacheEntryOptions());
}
}
}

38
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedStrategyStateStore.cs

@ -0,0 +1,38 @@
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
namespace LINGYUN.Abp.DataProtection.Stores;
public class DataProtectedStrategyStateStore : IDataProtectedStrategyStateStore, ITransientDependency
{
private readonly IDataProtectedStrategyStateCache _cache;
public DataProtectedStrategyStateStore(IDataProtectedStrategyStateCache cache)
{
_cache = cache;
}
public async virtual Task<DataAccessStrategyState> GetOrNullAsync(string subjectName, string subjectId)
{
var cacheItem = await _cache.GetAsync(subjectName, subjectId);
if (cacheItem == null )
{
return null;
}
return new DataAccessStrategyState(
cacheItem.SubjectName,
new string[] { cacheItem.SubjectId },
cacheItem.Strategy);
}
public async virtual Task RemoveAsync(DataAccessStrategyState state)
{
await _cache.RemoveAsync(state);
}
public async virtual Task SetAsync(DataAccessStrategyState state)
{
await _cache.SetAsync(state);
}
}

5
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IDataProtectedResourceCache.cs → aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedResourceCache.cs

@ -1,7 +1,6 @@
using LINGYUN.Abp.DataProtection;
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace LINGYUN.Abp.DataProtectionManagement;
namespace LINGYUN.Abp.DataProtection.Stores;
public interface IDataProtectedResourceCache
{
/// <summary>

2
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectedResourceStore.cs → aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedResourceStore.cs

@ -1,6 +1,6 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.DataProtection;
namespace LINGYUN.Abp.DataProtection.Stores;
public interface IDataProtectedResourceStore
{
Task SetAsync(DataAccessResource resource);

12
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedStrategyStateCache.cs

@ -0,0 +1,12 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.DataProtection.Stores;
public interface IDataProtectedStrategyStateCache
{
Task SetAsync(DataAccessStrategyState state);
Task RemoveAsync(DataAccessStrategyState state);
Task<DataAccessStrategyStateCacheItem> GetAsync(string subjectName, string subjectId);
}

12
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedStrategyStateStore.cs

@ -0,0 +1,12 @@
using System.Threading.Tasks;
namespace LINGYUN.Abp.DataProtection.Stores;
public interface IDataProtectedStrategyStateStore
{
Task SetAsync(DataAccessStrategyState state);
Task RemoveAsync(DataAccessStrategyState state);
Task<DataAccessStrategyState> GetOrNullAsync(string subjectName, string subjectId);
}

3
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessClientIdContributor.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using LINGYUN.Abp.DataProtection.Stores;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

1
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessOrganizationUnitContributor.cs

@ -1,4 +1,5 @@
using LINGYUN.Abp.Authorization.Permissions;
using LINGYUN.Abp.DataProtection.Stores;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Linq;

3
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessRoleNameContributor.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using LINGYUN.Abp.DataProtection.Stores;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

39
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessStrategyRoleNameContributor.cs

@ -0,0 +1,39 @@
using LINGYUN.Abp.DataProtection.Stores;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Users;
namespace LINGYUN.Abp.DataProtection.Subjects;
/// <summary>
/// 角色数据权限策略
/// </summary>
public class DataAccessStrategyRoleNameContributor : IDataAccessStrategyContributor
{
public string Name => RolePermissionValueProvider.ProviderName;
public async virtual Task<DataAccessStrategyState> GetOrNullAsync(DataAccessStrategyContributorContext context)
{
var states = new List<DataAccessStrategyState>();
var currentUser = context.ServiceProvider.GetRequiredService<ICurrentUser>();
if (!currentUser.IsAuthenticated)
{
return null;
}
var store = context.ServiceProvider.GetRequiredService<IDataProtectedStrategyStateStore>();
foreach (var userRole in currentUser.Roles)
{
var strategyState = await store.GetOrNullAsync(Name, userRole);
if (strategyState != null)
{
states.Add(strategyState);
}
}
// 多个角色配置过策略时, 取权重最大的策略生效
return states.OrderByDescending(x => x.Strategy).FirstOrDefault();
}
}

3
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessUserIdContributor.cs

@ -1,4 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using LINGYUN.Abp.DataProtection.Stores;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

5328
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250402083655_Upgrade-Abp-Framework-To-9.1.1.Designer.cs

File diff suppressed because it is too large

41
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250402083655_Upgrade-Abp-Framework-To-9.1.1.cs

@ -0,0 +1,41 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migrations
{
/// <inheritdoc />
public partial class UpgradeAbpFrameworkTo911 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<DateTime>(
name: "CreationTime",
table: "AbpRoles",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
migrationBuilder.AddColumn<DateTime>(
name: "CreationTime",
table: "AbpClaimTypes",
type: "datetime(6)",
nullable: false,
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "CreationTime",
table: "AbpRoles");
migrationBuilder.DropColumn(
name: "CreationTime",
table: "AbpClaimTypes");
}
}
}

5328
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250403031044_Change-Auth-Data-Type.Designer.cs

File diff suppressed because it is too large

38
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250403031044_Change-Auth-Data-Type.cs

@ -0,0 +1,38 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migrations
{
/// <inheritdoc />
public partial class ChangeAuthDataType : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "Demo_Books",
type: "json",
nullable: false,
oldClrType: typeof(string),
oldType: "longtext")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "Demo_Books",
type: "longtext",
nullable: false,
oldClrType: typeof(string),
oldType: "json")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
}
}
}

5388
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250403085116_Add-Subject-Strategy.Designer.cs

File diff suppressed because it is too large

49
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250403085116_Add-Subject-Strategy.cs

@ -0,0 +1,49 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migrations
{
/// <inheritdoc />
public partial class AddSubjectStrategy : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "AbpAuthSubjectStrategys",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
IsEnabled = table.Column<bool>(type: "tinyint(1)", nullable: false),
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
SubjectName = table.Column<string>(type: "varchar(30)", maxLength: 30, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
SubjectId = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
Strategy = table.Column<int>(type: "int", nullable: false),
ExtraProperties = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
ConcurrencyStamp = table.Column<string>(type: "varchar(40)", maxLength: 40, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationTime = table.Column<DateTime>(type: "datetime(6)", nullable: false),
CreatorId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
LastModificationTime = table.Column<DateTime>(type: "datetime(6)", nullable: true),
LastModifierId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci")
},
constraints: table =>
{
table.PrimaryKey("PK_AbpAuthSubjectStrategys", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "AbpAuthSubjectStrategys");
}
}
}

5442
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250407032556_Add-Book-Auth.Designer.cs

File diff suppressed because it is too large

85
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250407032556_Add-Book-Auth.cs

@ -0,0 +1,85 @@
using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migrations
{
/// <inheritdoc />
public partial class AddBookAuth : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "Demo_Books",
type: "longtext",
nullable: false,
oldClrType: typeof(string),
oldType: "json")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "Demo_BooksAuths",
columns: table => new
{
Id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
TenantId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
EntityId = table.Column<Guid>(type: "char(64)", maxLength: 64, nullable: false, collation: "ascii_general_ci"),
EntityType = table.Column<string>(type: "varchar(128)", maxLength: 128, nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Role = table.Column<string>(type: "varchar(32)", maxLength: 32, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
OrganizationUnit = table.Column<string>(type: "varchar(20)", maxLength: 20, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_Demo_BooksAuths", x => x.Id);
table.ForeignKey(
name: "FK_Demo_BooksAuths_Demo_Books_EntityId",
column: x => x.EntityId,
principalTable: "Demo_Books",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_Demo_BooksAuths_EntityId",
table: "Demo_BooksAuths",
column: "EntityId");
migrationBuilder.CreateIndex(
name: "IX_Demo_BooksAuths_OrganizationUnit",
table: "Demo_BooksAuths",
column: "OrganizationUnit");
migrationBuilder.CreateIndex(
name: "IX_Demo_BooksAuths_Role",
table: "Demo_BooksAuths",
column: "Role");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Demo_BooksAuths");
migrationBuilder.AlterColumn<string>(
name: "ExtraProperties",
table: "Demo_Books",
type: "json",
nullable: false,
oldClrType: typeof(string),
oldType: "longtext")
.Annotation("MySql:CharSet", "utf8mb4")
.OldAnnotation("MySql:CharSet", "utf8mb4");
}
}
}

124
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/SingleMigrationsDbContextModelSnapshot.cs

@ -19,7 +19,7 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql)
.HasAnnotation("ProductVersion", "9.0.0")
.HasAnnotation("ProductVersion", "9.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
@ -310,6 +310,66 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio
b.ToTable("AbpAuthRoleEntityRules", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.SubjectStrategy", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("char(36)");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.IsRequired()
.HasMaxLength(40)
.HasColumnType("varchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<Guid?>("CreatorId")
.HasColumnType("char(36)")
.HasColumnName("CreatorId");
b.Property<string>("ExtraProperties")
.IsRequired()
.HasColumnType("longtext")
.HasColumnName("ExtraProperties");
b.Property<bool>("IsEnabled")
.HasColumnType("tinyint(1)");
b.Property<DateTime?>("LastModificationTime")
.HasColumnType("datetime(6)")
.HasColumnName("LastModificationTime");
b.Property<Guid?>("LastModifierId")
.HasColumnType("char(36)")
.HasColumnName("LastModifierId");
b.Property<int>("Strategy")
.HasColumnType("int");
b.Property<string>("SubjectId")
.HasMaxLength(64)
.HasColumnType("varchar(64)")
.HasColumnName("SubjectId");
b.Property<string>("SubjectName")
.IsRequired()
.HasMaxLength(30)
.HasColumnType("varchar(30)")
.HasColumnName("SubjectName");
b.Property<Guid?>("TenantId")
.HasColumnType("char(36)")
.HasColumnName("TenantId");
b.HasKey("Id");
b.ToTable("AbpAuthSubjectStrategys", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Demo.Authors.Author", b =>
{
b.Property<Guid>("Id")
@ -434,6 +494,49 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio
b.ToTable("Demo_Books", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Demo.Books.BookAuth", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint");
MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property<long>("Id"));
b.Property<Guid>("EntityId")
.HasMaxLength(64)
.HasColumnType("char(64)")
.HasColumnName("EntityId");
b.Property<string>("EntityType")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("varchar(128)")
.HasColumnName("EntityType");
b.Property<string>("OrganizationUnit")
.HasMaxLength(20)
.HasColumnType("varchar(20)")
.HasColumnName("OrganizationUnit");
b.Property<string>("Role")
.HasMaxLength(32)
.HasColumnType("varchar(32)")
.HasColumnName("Role");
b.Property<Guid?>("TenantId")
.HasColumnType("char(36)");
b.HasKey("Id");
b.HasIndex("EntityId");
b.HasIndex("OrganizationUnit");
b.HasIndex("Role");
b.ToTable("Demo_BooksAuths", (string)null);
});
modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b =>
{
b.Property<Guid>("Id")
@ -3754,6 +3857,10 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio
.HasColumnType("varchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<string>("Description")
.HasMaxLength(256)
.HasColumnType("varchar(256)");
@ -3829,6 +3936,10 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio
.HasColumnType("varchar(40)")
.HasColumnName("ConcurrencyStamp");
b.Property<DateTime>("CreationTime")
.HasColumnType("datetime(6)")
.HasColumnName("CreationTime");
b.Property<int>("EntityVersion")
.HasColumnType("int");
@ -5006,6 +5117,17 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migratio
.IsRequired();
});
modelBuilder.Entity("LINGYUN.Abp.Demo.Books.BookAuth", b =>
{
b.HasOne("LINGYUN.Abp.Demo.Books.Book", "Entity")
.WithMany()
.HasForeignKey("EntityId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Entity");
});
modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b =>
{
b.HasOne("LINGYUN.Abp.Gdpr.GdprRequest", null)

21
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/ApplicationSingleDataSeederWorker.cs

@ -0,0 +1,21 @@
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Data;
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.DataSeeder;
public class ApplicationSingleDataSeederWorker : BackgroundService
{
protected IDataSeeder DataSeeder { get; }
public ApplicationSingleDataSeederWorker(IDataSeeder dataSeeder)
{
DataSeeder = dataSeeder;
}
protected async override Task ExecuteAsync(CancellationToken stoppingToken)
{
await DataSeeder.SeedAsync();
}
}

29
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/ClientDataSeederContributor.cs

@ -7,6 +7,8 @@ using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.OpenIddict.Applications;
using Volo.Abp.OpenIddict.Scopes;
using Volo.Abp.PermissionManagement;
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.DataSeeder;
@ -14,7 +16,10 @@ namespace LY.MicroService.Applications.Single.EntityFrameworkCore.DataSeeder;
public class ClientDataSeederContributor : IDataSeedContributor, ITransientDependency
{
private readonly IOpenIddictApplicationManager _applicationManager;
private readonly IOpenIddictApplicationRepository _applicationRepository;
private readonly IOpenIddictScopeManager _scopeManager;
private readonly IOpenIddictScopeRepository _scopeRepository;
private readonly IPermissionDataSeeder _permissionDataSeeder;
private readonly IConfiguration _configuration;
@ -22,13 +27,17 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen
public ClientDataSeederContributor(
IOpenIddictApplicationManager applicationManager,
IOpenIddictApplicationRepository applicationRepository,
IOpenIddictScopeManager scopeManager,
IOpenIddictScopeRepository scopeRepository,
IPermissionDataSeeder permissionDataSeeder,
IConfiguration configuration,
ICurrentTenant currentTenant)
{
_applicationManager = applicationManager;
_applicationRepository = applicationRepository;
_scopeManager = scopeManager;
_scopeRepository = scopeRepository;
_permissionDataSeeder = permissionDataSeeder;
_configuration = configuration;
_currentTenant = currentTenant;
@ -52,7 +61,7 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen
private async Task CreateScopeAsync(string scope)
{
if (await _scopeManager.FindByNameAsync(scope) == null)
if (await _scopeRepository.FindByNameAsync(scope) == null)
{
await _scopeManager.CreateAsync(new OpenIddictScopeDescriptor()
{
@ -80,7 +89,7 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen
{
var vueClientRootUrl = configurationSection["VueAdmin:RootUrl"].EnsureEndsWith('/');
if (await _applicationManager.FindByClientIdAsync(vueClientId) == null)
if (await _applicationRepository.FindByClientIdAsync(vueClientId) == null)
{
await _applicationManager.CreateAsync(new OpenIddictApplicationDescriptor
{
@ -103,10 +112,10 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen
{
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.Endpoints.Device,
OpenIddictConstants.Permissions.Endpoints.DeviceAuthorization,
OpenIddictConstants.Permissions.Endpoints.Introspection,
OpenIddictConstants.Permissions.Endpoints.Revocation,
OpenIddictConstants.Permissions.Endpoints.Logout,
OpenIddictConstants.Permissions.Endpoints.EndSession,
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
OpenIddictConstants.Permissions.GrantTypes.Implicit,
@ -144,7 +153,7 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen
var internalServiceClientId = configurationSection["InternalService:ClientId"];
if (!internalServiceClientId.IsNullOrWhiteSpace())
{
if (await _applicationManager.FindByClientIdAsync(internalServiceClientId) == null)
if (await _applicationRepository.FindByClientIdAsync(internalServiceClientId) == null)
{
await _applicationManager.CreateAsync(new OpenIddictApplicationDescriptor
{
@ -158,10 +167,10 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen
{
OpenIddictConstants.Permissions.Endpoints.Authorization,
OpenIddictConstants.Permissions.Endpoints.Token,
OpenIddictConstants.Permissions.Endpoints.Device,
OpenIddictConstants.Permissions.Endpoints.DeviceAuthorization,
OpenIddictConstants.Permissions.Endpoints.Introspection,
OpenIddictConstants.Permissions.Endpoints.Revocation,
OpenIddictConstants.Permissions.Endpoints.Logout,
OpenIddictConstants.Permissions.Endpoints.EndSession,
OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,
OpenIddictConstants.Permissions.GrantTypes.Implicit,
@ -189,9 +198,9 @@ public class ClientDataSeederContributor : IDataSeedContributor, ITransientDepen
});
var internalServicePermissions = new string[2]
{
"AbpIdentity.UserLookup","AbpIdentity.Users"
};
{
"AbpIdentity.UserLookup","AbpIdentity.Users"
};
await _permissionDataSeeder.SeedAsync(ClientPermissionValueProvider.ProviderName, internalServiceClientId, internalServicePermissions);
}
}

53
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/DataSeeder/IdentityDataSeedContributor.cs

@ -0,0 +1,53 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System.Threading.Tasks;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Guids;
using Volo.Abp.Identity;
using Volo.Abp.MultiTenancy;
namespace LY.MicroService.Applications.Single.EntityFrameworkCore.DataSeeder;
public class IdentityDataSeedContributor : IDataSeedContributor, ITransientDependency
{
public ILogger<IdentityDataSeedContributor> Logger { protected get; set; }
protected ICurrentTenant CurrentTenant { get; }
protected IGuidGenerator GuidGenerator { get; }
protected IdentityRoleManager IdentityRoleManager { get; }
public IdentityDataSeedContributor(
ICurrentTenant currentTenant,
IGuidGenerator guidGenerator,
IdentityRoleManager identityRoleManager)
{
CurrentTenant = currentTenant;
GuidGenerator = guidGenerator;
IdentityRoleManager = identityRoleManager;
Logger = NullLogger<IdentityDataSeedContributor>.Instance;
}
public async virtual Task SeedAsync(DataSeedContext context)
{
using (CurrentTenant.Change(context.TenantId))
{
Logger.LogInformation("Seeding the default role Users...");
if (await IdentityRoleManager.FindByNameAsync("Users") == null)
{
await IdentityRoleManager.CreateAsync(
new IdentityRole(
GuidGenerator.Create(),
"Users",
context.TenantId)
{
IsDefault = true,
IsPublic = true,
IsStatic = true,
});
}
}
}
}

2
aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore/SingleMigrationsEntityFrameworkCoreModule.cs

@ -11,6 +11,7 @@ using LINGYUN.Abp.TextTemplating.EntityFrameworkCore;
using LINGYUN.Abp.WebhooksManagement.EntityFrameworkCore;
using LINGYUN.Abp.WeChat;
using LINGYUN.Platform.EntityFrameworkCore;
using LY.MicroService.Applications.Single.EntityFrameworkCore.DataSeeder;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Modularity;
@ -44,5 +45,6 @@ public class SingleMigrationsEntityFrameworkCoreModule : AbpModule
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAbpDbContext<SingleMigrationsDbContext>();
context.Services.AddHostedService<ApplicationSingleDataSeederWorker>();
}
}

11
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/SubjectStrategyDto.cs

@ -0,0 +1,11 @@
using LINGYUN.Abp.DataProtection;
namespace LINGYUN.Abp.DataProtectionManagement;
public class SubjectStrategyDto
{
public bool IsEnabled { get; set; }
public string SubjectName { get; set; }
public string SubjectId { get; set; }
public DataAccessStrategy Strategy { get; set; }
}

15
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/SubjectStrategyGetInput.cs

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation;
namespace LINGYUN.Abp.DataProtectionManagement;
public class SubjectStrategyGetInput
{
[Required]
[DynamicStringLength(typeof(SubjectStrategyConsts), nameof(SubjectStrategyConsts.MaxSubjectNameLength))]
public string SubjectName { get; set; }
[Required]
[DynamicStringLength(typeof(SubjectStrategyConsts), nameof(SubjectStrategyConsts.MaxSubjectIdLength))]
public string SubjectId { get; set; }
}

20
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Dto/SubjectStrategySetInput.cs

@ -0,0 +1,20 @@
using LINGYUN.Abp.DataProtection;
using System.ComponentModel.DataAnnotations;
using Volo.Abp.Validation;
namespace LINGYUN.Abp.DataProtectionManagement;
public class SubjectStrategySetInput
{
public bool IsEnabled { get; set; }
[Required]
[DynamicStringLength(typeof(SubjectStrategyConsts), nameof(SubjectStrategyConsts.MaxSubjectNameLength))]
public string SubjectName { get; set; }
[Required]
[DynamicStringLength(typeof(SubjectStrategyConsts), nameof(SubjectStrategyConsts.MaxSubjectNameLength))]
public string SubjectId { get; set; }
public DataAccessStrategy Strategy { get; set; }
}

11
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/ISubjectStrategyAppService.cs

@ -0,0 +1,11 @@
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
namespace LINGYUN.Abp.DataProtectionManagement;
public interface ISubjectStrategyAppService : IApplicationService
{
Task<SubjectStrategyDto> GetAsync(SubjectStrategyGetInput input);
Task<SubjectStrategyDto> SetAsync(SubjectStrategySetInput input);
}

3
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionDefinitionProvider.cs

@ -26,6 +26,9 @@ public class DataProtectionManagementPermissionDefinitionProvider : PermissionDe
ouEntityRule.AddChild(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Create, L("Permission:Create"));
ouEntityRule.AddChild(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Update, L("Permission:Update"));
ouEntityRule.AddChild(DataProtectionManagementPermissionNames.OrganizationUnitEntityRule.Delete, L("Permission:Delete"));
var subjectStrategy = group.AddPermission(DataProtectionManagementPermissionNames.SubjectStrategy.Default, L("Permission:Strategy"));
subjectStrategy.AddChild(DataProtectionManagementPermissionNames.SubjectStrategy.Change, L("Permission:ChangeStrategy"));
}
private static LocalizableString L(string name)

6
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application.Contracts/LINGYUN/Abp/DataProtectionManagement/Permissions/DataProtectionManagementPermissionNames.cs

@ -30,6 +30,12 @@ public static class DataProtectionManagementPermissionNames
public const string Delete = Default + ".Delete";
}
public static class SubjectStrategy
{
public const string Default = GroupName + ".SubjectStrategy";
public const string Change = Default + ".Change";
}
public static string[] GetAll()
{
return ReflectionHelper.GetPublicConstantsRecursively(typeof(DataProtectionManagementPermissionNames));

2
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/DataProtectionManagementApplicationMappingProfile.cs

@ -14,6 +14,8 @@ public class DataProtectionManagementApplicationMappingProfile :Profile
.ForMember(dto => dto.AccessedProperties, map => map.MapFrom(src => MapToArray(src.AccessedProperties)));
CreateMap<OrganizationUnitEntityRule, OrganizationUnitEntityRuleDto>()
.ForMember(dto => dto.AccessedProperties, map => map.MapFrom(src => MapToArray(src.AccessedProperties)));
CreateMap<SubjectStrategy, SubjectStrategyDto>();
}
private string[] MapToArray(string val)

2
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/OrganizationUnitEntityRuleAppService.cs

@ -64,6 +64,7 @@ public class OrganizationUnitEntityRuleAppService : DataProtectionManagementAppl
await EventBus.PublishAsync(
new DataAccessResourceChangeEvent(
entityRule.IsEnabled,
new DataAccessResource(
OrganizationUnitPermissionValueProvider.ProviderName,
entityRule.OrgCode,
@ -102,6 +103,7 @@ public class OrganizationUnitEntityRuleAppService : DataProtectionManagementAppl
await EventBus.PublishAsync(
new DataAccessResourceChangeEvent(
entityRule.IsEnabled,
new DataAccessResource(
OrganizationUnitPermissionValueProvider.ProviderName,
entityRule.OrgCode,

2
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/RoleEntityRuleAppService.cs

@ -64,6 +64,7 @@ public class RoleEntityRuleAppService : DataProtectionManagementApplicationServi
await EventBus.PublishAsync(
new DataAccessResourceChangeEvent(
entityRule.IsEnabled,
new DataAccessResource(
RolePermissionValueProvider.ProviderName,
entityRule.RoleName,
@ -103,6 +104,7 @@ public class RoleEntityRuleAppService : DataProtectionManagementApplicationServi
await EventBus.PublishAsync(
new DataAccessResourceChangeEvent(
entityRule.IsEnabled,
new DataAccessResource(
RolePermissionValueProvider.ProviderName,
entityRule.RoleName,

63
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/LINGYUN/Abp/DataProtectionManagement/SubjectStrategyAppService.cs

@ -0,0 +1,63 @@
using LINGYUN.Abp.DataProtection.Stores;
using LINGYUN.Abp.DataProtectionManagement.Permissions;
using Microsoft.AspNetCore.Authorization;
using System.Threading.Tasks;
namespace LINGYUN.Abp.DataProtectionManagement;
[Authorize(DataProtectionManagementPermissionNames.SubjectStrategy.Default)]
public class SubjectStrategyAppService : DataProtectionManagementApplicationServiceBase, ISubjectStrategyAppService
{
private readonly ISubjectStrategyRepository _repository;
private readonly IDataProtectedStrategyStateStore _strategyStateStore;
public SubjectStrategyAppService(
ISubjectStrategyRepository repository,
IDataProtectedStrategyStateStore strategyStateStore)
{
_repository = repository;
_strategyStateStore = strategyStateStore;
}
public async virtual Task<SubjectStrategyDto> GetAsync(SubjectStrategyGetInput input)
{
var subjectStrategy = await _repository.FindBySubjectAsync(input.SubjectName, input.SubjectId);
return ObjectMapper.Map<SubjectStrategy, SubjectStrategyDto>(subjectStrategy);
}
[Authorize(DataProtectionManagementPermissionNames.SubjectStrategy.Change)]
public async virtual Task<SubjectStrategyDto> SetAsync(SubjectStrategySetInput input)
{
var subjectStrategy = await _repository.FindBySubjectAsync(input.SubjectName, input.SubjectId);
if (subjectStrategy == null)
{
subjectStrategy = new SubjectStrategy(
GuidGenerator.Create(),
input.SubjectName,
input.SubjectId,
input.Strategy,
CurrentTenant.Id)
{
IsEnabled = input.IsEnabled
};
await _repository.InsertAsync(subjectStrategy);
}
else
{
subjectStrategy.IsEnabled = input.IsEnabled;
subjectStrategy.Strategy = input.Strategy;
await _repository.UpdateAsync(subjectStrategy);
}
await _strategyStateStore.SetAsync(
new DataProtection.DataAccessStrategyState(
subjectStrategy.SubjectName,
new string[] { subjectStrategy .SubjectId},
subjectStrategy.Strategy));
return ObjectMapper.Map<SubjectStrategy, SubjectStrategyDto>(subjectStrategy);
}
}

6
aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/System/Linq/Expressions/ExpressionFuncExtensions.cs → aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Application/System/Linq/Expressions/ExpressionFuncExtensions.cs

@ -1,6 +1,6 @@
namespace System.Linq.Expressions;
public static class ExpressionFuncExtensions
internal static class ExpressionFuncExtensions
{
public static Expression<Func<T, bool>> AndIf<T>(
this Expression<Func<T, bool>> first,
@ -9,7 +9,7 @@ public static class ExpressionFuncExtensions
{
if (condition)
{
return ExpressionFuncExtender.AndAlso(first, second);
return first.And(second);
}
return first;
@ -22,7 +22,7 @@ public static class ExpressionFuncExtensions
{
if (condition)
{
return ExpressionFuncExtender.OrElse(first, second);
return first.Or(second);
}
return first;

2
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/Localization/Resources/en.json

@ -8,6 +8,8 @@
"Permission:Create": "Create",
"Permission:Update": "Update",
"Permission:Delete": "Delete",
"Permission:Strategy": "Strategy",
"Permission:ChangeStrategy": "Change Strategy",
"DataProtectionManagement:001100": "There already exists an entity type definition named {Name}!",
"DataProtectionManagement:001200": "The entity type already has a property definition named {Name}!",
"DataProtectionManagement:002100": "The {Operation} access rule for entity {Name} has been assigned to role {RoleName}!",

2
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/Localization/Resources/zh-Hans.json

@ -8,6 +8,8 @@
"Permission:Create": "新增",
"Permission:Update": "修改",
"Permission:Delete": "删除",
"Permission:Strategy": "数据权限策略",
"Permission:ChangeStrategy": "变更策略",
"DataProtectionManagement:001100": "已经存在名为 {Name} 的实体类型定义!",
"DataProtectionManagement:001200": "实体类型已经存在名为 {Name} 的属性定义!",
"DataProtectionManagement:002100": "已为角色 {RoleName} 分配了实体 {Name} 的 {Operation} 访问规则!",

7
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain.Shared/LINGYUN/Abp/DataProtectionManagement/SubjectStrategyConsts.cs

@ -0,0 +1,7 @@
namespace LINGYUN.Abp.DataProtectionManagement;
public static class SubjectStrategyConsts
{
public static int MaxSubjectNameLength { get; set; } = 30;
public static int MaxSubjectIdLength { get; set; } = 64;
}

34
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataAccessStrategyStateSynchronizer.cs

@ -0,0 +1,34 @@
using LINGYUN.Abp.DataProtection;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Uow;
namespace LINGYUN.Abp.DataProtectionManagement;
public class DataAccessStrategyStateSynchronizer : IDistributedEventHandler<DataAccessResourceChangeEvent>, ITransientDependency
{
private readonly ISubjectStrategyRepository _strategyRepository;
public DataAccessStrategyStateSynchronizer(ISubjectStrategyRepository strategyRepository)
{
_strategyRepository = strategyRepository;
}
[UnitOfWork]
public async virtual Task HandleEventAsync(DataAccessResourceChangeEvent eventData)
{
if (eventData.IsEnabled)
{
var subjectStrategy = await _strategyRepository.FindBySubjectAsync(
eventData.Resource.SubjectName,
eventData.Resource.SubjectId);
if (subjectStrategy != null)
{
subjectStrategy.Strategy = DataAccessStrategy.Custom;
await _strategyRepository.UpdateAsync(subjectStrategy);
}
}
}
}

14
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/ISubjectStrategyRepository.cs

@ -0,0 +1,14 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
namespace LINGYUN.Abp.DataProtectionManagement;
public interface ISubjectStrategyRepository : IBasicRepository<SubjectStrategy, Guid>
{
Task<SubjectStrategy> FindBySubjectAsync(
string subjectName,
string subjectId,
CancellationToken cancellationToken = default);
}

41
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/SubjectStrategy.cs

@ -0,0 +1,41 @@
using LINGYUN.Abp.DataProtection;
using System;
using Volo.Abp;
using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.MultiTenancy;
namespace LINGYUN.Abp.DataProtectionManagement;
public class SubjectStrategy : AuditedAggregateRoot<Guid>, IMultiTenant
{
public virtual bool IsEnabled { get; set; }
public virtual Guid? TenantId { get; protected set; }
public virtual string SubjectName { get; protected set; }
public virtual string SubjectId { get; protected set; }
public virtual DataAccessStrategy Strategy { get; set; }
protected SubjectStrategy()
{
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
public SubjectStrategy(
Guid id,
string subjectName,
string subjectId,
DataAccessStrategy strategy,
Guid? tenantId = null)
: base(id)
{
IsEnabled = true;
SubjectName = Check.NotNullOrWhiteSpace(subjectName, nameof(subjectName), SubjectStrategyConsts.MaxSubjectNameLength);
SubjectId = Check.NotNullOrWhiteSpace(subjectId, nameof(subjectId), SubjectStrategyConsts.MaxSubjectIdLength);
Strategy = strategy;
TenantId = tenantId;
ExtraProperties = new ExtraPropertyDictionary();
this.SetDefaultsForExtraProperties();
}
}

15
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementDbContextModelCreatingExtensions.cs

@ -148,6 +148,21 @@ namespace LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore
b.ConfigureByConvention();
});
builder.Entity<SubjectStrategy>(b =>
{
b.ToTable(options.TablePrefix + "SubjectStrategys", options.Schema);
b.Property(p => p.SubjectName)
.HasColumnName(nameof(SubjectStrategy.SubjectName))
.HasMaxLength(SubjectStrategyConsts.MaxSubjectNameLength)
.IsRequired();
b.Property(p => p.SubjectId)
.HasColumnName(nameof(SubjectStrategy.SubjectId))
.HasMaxLength(SubjectStrategyConsts.MaxSubjectIdLength);
b.ConfigureByConvention();
});
}
}
}

2
aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.EntityFrameworkCore/LINGYUN/Abp/DataProtectionManagement/EntityFrameworkCore/AbpDataProtectionManagementEntityFrameworkCoreModule.cs

@ -19,6 +19,8 @@ public class AbpDataProtectionManagementEntityFrameworkCoreModule : AbpModule
options.AddRepository<RoleEntityRule, EfCoreRoleEntityRuleRepository>();
options.AddRepository<OrganizationUnitEntityRule, EfCoreOrganizationUnitEntityRuleRepository>();
options.AddRepository<SubjectStrategy, EfCoreSubjectStrategyRepository>();
options.AddDefaultRepositories();
});
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save