diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN.Abp.DataProtection.Abstractions.csproj b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN.Abp.DataProtection.Abstractions.csproj
index 7a533fe04..059aa0313 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN.Abp.DataProtection.Abstractions.csproj
+++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN.Abp.DataProtection.Abstractions.csproj
@@ -26,6 +26,7 @@
+
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AbpDataProtectionAbstractionsModule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AbpDataProtectionAbstractionsModule.cs
index e698f6b06..c304bf441 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AbpDataProtectionAbstractionsModule.cs
+++ b/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(AsyncLocalCurrentDataAccessAccessor.Instance);
+
Configure(options =>
{
options.FileSets.AddEmbedded();
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AsyncLocalCurrentDataAccessAccessor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/AsyncLocalCurrentDataAccessAccessor.cs
new file mode 100644
index 000000000..45e15a20b
--- /dev/null
+++ b/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 _currentScope;
+ private AsyncLocalCurrentDataAccessAccessor()
+ {
+ _currentScope = new AsyncLocal();
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessEntityAuthCreateEvent.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessEntityAuthCreateEvent.cs
new file mode 100644
index 000000000..0b2bc253b
--- /dev/null
+++ b/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;
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResource.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResource.cs
index 786887299..5572b1c6d 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResource.cs
+++ b/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();
}
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResourceChangeEvent.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResourceChangeEvent.cs
index c2df4141a..aa23d1053 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessResourceChangeEvent.cs
+++ b/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;
}
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessScope.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessScope.cs
new file mode 100644
index 000000000..f08e63112
--- /dev/null
+++ b/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>(static (state) =>
+ {
+ var (currentDataAccessAccessor, parentScope) = state;
+ currentDataAccessAccessor.Current = parentScope;
+ }, (_currentDataAccessAccessor, parentScope));
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessStrategy.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessStrategy.cs
new file mode 100644
index 000000000..8360731f6
--- /dev/null
+++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessStrategy.cs
@@ -0,0 +1,31 @@
+namespace LINGYUN.Abp.DataProtection;
+///
+/// 数据访问策略
+///
+public enum DataAccessStrategy
+{
+ ///
+ /// 可以访问所有数据
+ ///
+ All,
+ ///
+ /// 自定义规则
+ ///
+ Custom,
+ ///
+ /// 仅当前用户
+ ///
+ CurrentUser,
+ ///
+ /// 仅当前用户角色
+ ///
+ CurrentRoles,
+ ///
+ /// 仅当前用户组织机构
+ ///
+ CurrentOrganizationUnits,
+ ///
+ /// 仅当前用户组织机构及下级机构
+ ///
+ CurrentAndSubOrganizationUnits,
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessStrategyState.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataAccessStrategyState.cs
new file mode 100644
index 000000000..d822c9960
--- /dev/null
+++ b/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
+{
+ ///
+ /// 权限主体
+ ///
+ public string SubjectName { get; set; }
+
+ ///
+ /// 权限主体标识
+ ///
+ public string[] SubjectKeys { get; set; }
+
+ ///
+ /// 权限策略
+ ///
+ public DataAccessStrategy Strategy { get; set; }
+ public DataAccessStrategyState()
+ {
+
+ }
+ public DataAccessStrategyState(
+ string subjectName,
+ string[] subjectKeys,
+ DataAccessStrategy strategy)
+ {
+ SubjectName = subjectName;
+ SubjectKeys = subjectKeys;
+ Strategy = strategy;
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataProtectedAttribute.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataProtectedAttribute.cs
index 6de026f74..75e63e574 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DataProtectedAttribute.cs
+++ b/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;
}
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DisableDataProtectedAttribute.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DisableDataProtectedAttribute.cs
index 052d53fea..d5abe78ce 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/DisableDataProtectedAttribute.cs
+++ b/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;
- }
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/ICurrentDataAccessAccessor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/ICurrentDataAccessAccessor.cs
new file mode 100644
index 000000000..300afcd8a
--- /dev/null
+++ b/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; }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataAccessScope.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataAccessScope.cs
new file mode 100644
index 000000000..354a2e34c
--- /dev/null
+++ b/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);
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtected.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtected.cs
index 2b3829e2c..986f4f508 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/IDataProtected.cs
+++ b/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; }
}
\ No newline at end of file
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/en.json b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/en.json
index a07a45eff..e38da5e27 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/en.json
+++ b/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"
}
}
\ No newline at end of file
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/zh-Hans.json b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/zh-Hans.json
index 5e719bf94..a914fbdfa 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Abstractions/LINGYUN/Abp/DataProtection/Localization/Resources/zh-Hans.json
+++ b/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": "仅当前用户组织机构及下级机构"
}
}
\ No newline at end of file
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/FodyWeavers.xml b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/FodyWeavers.xml
deleted file mode 100644
index 1715698cc..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/FodyWeavers.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN.Abp.DataProtection.Application.Contracts.csproj b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN.Abp.DataProtection.Application.Contracts.csproj
deleted file mode 100644
index 5fb9d1dc9..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN.Abp.DataProtection.Application.Contracts.csproj
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
-
- netstandard2.0;netstandard2.1;net8.0;net9.0
- LINGYUN.Abp.DataProtection.Application.Contracts
- LINGYUN.Abp.DataProtection.Application.Contracts
- false
- false
- false
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationContractsModule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationContractsModule.cs
deleted file mode 100644
index c15e35b94..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationContractsModule.cs
+++ /dev/null
@@ -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
-{
-
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityEnumInfoDto.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityEnumInfoDto.cs
deleted file mode 100644
index 58d981ca3..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityEnumInfoDto.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace LINGYUN.Abp.DataProtection;
-
-public class EntityEnumInfoDto
-{
- public string Key { get; set; }
- public object Value { get; set; }
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityPropertyInfoDto.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityPropertyInfoDto.cs
deleted file mode 100644
index 74af75176..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityPropertyInfoDto.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-namespace LINGYUN.Abp.DataProtection;
-
-public class EntityPropertyInfoDto
-{
- ///
- /// 名称
- ///
- public string Name { get; set; }
- ///
- /// 显示名称
- ///
- public string DisplayName { get; set; }
- ///
- /// 类型全名
- ///
- public string TypeFullName { get; set; }
- ///
- /// JavaScript类型
- ///
- public string JavaScriptType { get; set; }
- ///
- /// 枚举列表
- ///
- public EntityEnumInfoDto[] Enums { get; set; } = new EntityEnumInfoDto[0];
- ///
- /// 允许的过滤操作列表
- ///
- public DataAccessFilterOperate[] Operates { get; set; }
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoDto.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoDto.cs
deleted file mode 100644
index faf3f2937..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoDto.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace LINGYUN.Abp.DataProtection;
-
-public class EntityTypeInfoDto
-{
- ///
- /// 实体名称
- ///
- public string Name { get; set; }
- ///
- /// 显示名称
- ///
- public string DisplayName { get; set; }
- ///
- /// 可访问属性列表
- ///
- public EntityPropertyInfoDto[] Properties { get; set; } = new EntityPropertyInfoDto[0];
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoGetInput.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoGetInput.cs
deleted file mode 100644
index c6653682e..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/EntityTypeInfoGetInput.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-namespace LINGYUN.Abp.DataProtection;
-
-public class EntityTypeInfoGetInput
-{
- public DataAccessOperation Operation { get; set; }
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/IEntityTypeInfoAppService.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/IEntityTypeInfoAppService.cs
deleted file mode 100644
index 4ac0b4fc5..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application.Contracts/LINGYUN/Abp/DataProtection/IEntityTypeInfoAppService.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using System.Threading.Tasks;
-using Volo.Abp.Application.Services;
-
-namespace LINGYUN.Abp.DataProtection;
-
-public interface IEntityTypeInfoAppService : IApplicationService
-{
- ///
- /// 获取实体可访问规则
- ///
- ///
- ///
- Task GetEntityRuleAsync(EntityTypeInfoGetInput input);
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/FodyWeavers.xml b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/FodyWeavers.xml
deleted file mode 100644
index 1715698cc..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/FodyWeavers.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
\ No newline at end of file
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN.Abp.DataProtection.Application.csproj b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN.Abp.DataProtection.Application.csproj
deleted file mode 100644
index 632de70bd..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN.Abp.DataProtection.Application.csproj
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
- netstandard2.0;netstandard2.1;net8.0;net9.0
- LINGYUN.Abp.DataProtection.Application
- LINGYUN.Abp.DataProtection.Application
- false
- false
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationModule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationModule.cs
deleted file mode 100644
index f5bcff996..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/AbpDataProtectionApplicationModule.cs
+++ /dev/null
@@ -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
-{
-
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/EntityTypeInfoAppService.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/EntityTypeInfoAppService.cs
deleted file mode 100644
index 393c9b345..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/LINGYUN/Abp/DataProtection/EntityTypeInfoAppService.cs
+++ /dev/null
@@ -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 : ApplicationService, IEntityTypeInfoAppService
-{
- protected IDataAccessEntityTypeInfoProvider EntityTypeInfoProvider => LazyServiceProvider.GetRequiredService();
-
- [Authorize]
- public virtual async Task 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(),
- };
- }
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/System/NullableTypeExtensions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/System/NullableTypeExtensions.cs
deleted file mode 100644
index 1d650f831..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.Application/System/NullableTypeExtensions.cs
+++ /dev/null
@@ -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;
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWritePropertiesInterceptor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWritePropertiesInterceptor.cs
index b375afc9c..5744d3ca4 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectedWritePropertiesInterceptor.cs
+++ b/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;
+ }
}
}
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs
index 3b9d309a6..e6734b258 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs
+++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContext.cs
@@ -43,14 +43,14 @@ public abstract class AbpDataProtectionDbContext : AbpDbContext $"[{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());
+ //}
}
}
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContextModelBuilderExtensions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContextModelBuilderExtensions.cs
index 1db3a21b1..e2d172520 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionDbContextModelBuilderExtensions.cs
+++ b/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(this ModelBuilder builder)
+ where TEntity : class
+ where TEntityAuth : DataAuthBase
{
- public static void ConfigureLocalization(
- this ModelBuilder builder,
- Action optionsAction = null)
+ Check.NotNull(builder, nameof(builder));
+
+ var entityType = builder.Model.FindEntityType(typeof(TEntity)) ??
+ throw new ArgumentException("In the builder.ConfigureEntityAuth configuration entity mapping relationship before ().");
+
+ var entityTableName = entityType.GetTableName() ?? typeof(TEntity).Name;
+ var entitySchema = entityType.GetSchema();
+ var keyValueType = typeof(TKey);
+
+ builder.Entity(b =>
{
- Check.NotNull(builder, nameof(builder));
- }
+ b.ToTable(entityTableName + "Auths", entitySchema);
+
+ b.Property(p => p.EntityType)
+ .HasColumnName(nameof(DataAuthBase.EntityType))
+ .HasMaxLength(128)
+ .IsRequired();
+
+ if (keyValueType == typeof(string) || keyValueType == typeof(Guid))
+ {
+ b.Property(p => p.EntityId)
+ .HasColumnName(nameof(DataAuthBase.EntityId))
+ .HasMaxLength(64)
+ .IsRequired();
+ }
+ else
+ {
+ b.Property(p => p.EntityId)
+ .HasColumnName(nameof(DataAuthBase.EntityId))
+ .IsRequired();
+ }
+
+ b.Property(p => p.Role)
+ .HasColumnName(nameof(DataAuthBase.Role))
+ .HasMaxLength(32);
+ b.Property(p => p.OrganizationUnit)
+ .HasColumnName(nameof(DataAuthBase.OrganizationUnit))
+ .HasMaxLength(20);
+
+ b.HasIndex(p => p.Role);
+ b.HasIndex(p => p.OrganizationUnit);
+ });
}
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionEntityFrameworkCoreModule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionEntityFrameworkCoreModule.cs
index 46ac1c20f..f6c353d58 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/AbpDataProtectionEntityFrameworkCoreModule.cs
+++ b/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();
+ }
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataAccessStrategyFilterBuilder.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataAccessStrategyFilterBuilder.cs
new file mode 100644
index 000000000..84a2fd422
--- /dev/null
+++ b/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 Build(IQueryable entity, IQueryable entityAuth, DataAccessStrategyState state)
+ {
+ var parameterEntity = Expression.Parameter(typeof(TEntity), "e");
+ var parameterEntityAuth = Expression.Parameter(typeof(TEntityAuth), "ea");
+
+ var entityIdProperty = Expression.Property(parameterEntity, nameof(IEntity.Id));
+ var entityIdAuthProperty = Expression.Property(parameterEntityAuth, nameof(DataAuthBase.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>(currentUserExp, parameterEntity);
+ return entity.Where(currentUserFunc);
+
+ case DataAccessStrategy.CurrentRoles:
+ var roleProperty = Expression.Property(
+ parameterEntityAuth,
+ nameof(DataAuthBase.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>(roleFinalCondition, parameterEntityAuth)
+ );
+
+ var whereExistsCondition = Expression.Call(
+ typeof(Queryable),
+ "Where",
+ new Type[] { typeof(TEntity) },
+ entity.Expression,
+ Expression.Lambda>(
+ existsSubQueryWithRole, parameterEntity
+ )
+ );
+ return entity.Provider.CreateQuery(whereExistsCondition);
+ case DataAccessStrategy.CurrentOrganizationUnits:
+ var equalOrganizationUnits = _currentUser.FindOrganizationUnits();
+
+ var ouProperty = Expression.Property(
+ parameterEntityAuth,
+ nameof(DataAuthBase.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>(finalCondition, parameterEntityAuth)
+ );
+
+ var whereExistsConditionWithOu = Expression.Call(
+ typeof(Queryable),
+ "Where",
+ new Type[] { typeof(TEntity) },
+ entity.Expression,
+ Expression.Lambda>(
+ existsSubQueryWithOu, parameterEntity
+ )
+ );
+
+ return entity.Provider.CreateQuery(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>(
+ Expression.AndAlso(
+ Expression.Equal(
+ Expression.Property(parameterEntityAuth, nameof(DataAuthBase.EntityId)),
+ Expression.Property(parameterEntity, nameof(IEntity.Id))
+ ),
+ Expression.Call(
+ LikeMethodInfo,
+ dbFunctions,
+ Expression.Property(parameterEntityAuth, nameof(DataAuthBase.OrganizationUnit)),
+ Expression.Constant(ouCode + "%")
+ )
+ ),
+ parameterEntityAuth
+ )
+ )
+ )
+ .Aggregate(Expression.OrElse);
+
+ var startsWithWhereExistsConditionWithOu = Expression.Call(
+ typeof(Queryable),
+ "Where",
+ new Type[] { typeof(TEntity) },
+ entity.Expression,
+ Expression.Lambda>(filteredEntityAuth, parameterEntity)
+ );
+
+ return entity.Provider.CreateQuery(startsWithWhereExistsConditionWithOu);
+ }
+
+ return entity;
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepository.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepository.cs
index 7a002be8c..fc2217102 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepository.cs
+++ b/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 :
+public abstract class EfCoreDataProtectionRepository :
EfCoreRepository,
IDataProtectionRepository
where TDbContext : IEfCoreDbContext
- where TEntity : class, IEntity
+ where TEntity : class, IEntity, IDataProtected
+ where TEntityAuth : DataAuthBase
{
private readonly IDataAuthorizationService _dataAuthorizationService;
private readonly IEntityTypeFilterBuilder _entityTypeFilterBuilder;
private readonly IEntityPropertyResultBuilder _entityPropertyResultBuilder;
+ protected ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService();
+ protected IDataAccessStrategyFilterBuilder StrategyFilterBuilder => LazyServiceProvider.GetService();
+
protected EfCoreDataProtectionRepository(
[NotNull] IDbContextProvider dbContextProvider,
[NotNull] IDataAuthorizationService dataAuthorizationService,
@@ -37,12 +45,27 @@ public abstract class EfCoreDataProtectionRepository
public async override Task> GetQueryableAsync()
{
- var queryable = await base.GetQueryableAsync();
-
- var dataAccessFilterExp = await _entityTypeFilterBuilder.Build(DataAccessOperation.Read);
+ var dbContext = await GetDbContextAsync();
+ var dbSet = dbContext.Set();
+ var queryable = dbSet.AsQueryable().AsNoTrackingIf(!ShouldTrackingEntityChange());
+
+ var strategyFilterResult = await StrategyFilterBuilder?.Build(queryable, dbContext.Set());
+ if (strategyFilterResult != null && strategyFilterResult.Strategy != DataAccessStrategy.Custom)
+ {
+ // 根据配置的用户数据权限策略进行过滤
+ queryable = strategyFilterResult.Queryable;
+ }
+ else
+ {
+ // 根据配置的用户实体数据权限规则过滤
+ var dataAccessFilterExp = await _entityTypeFilterBuilder.Build(DataAccessOperation.Read);
+ queryable = queryable.Where(dataAccessFilterExp);
+ }
+
+ // 仅查询授权字段
var accessFieldExp = await _entityPropertyResultBuilder.Build(DataAccessOperation.Read);
- queryable = queryable.Where(dataAccessFilterExp).Select(accessFieldExp);
+ queryable = queryable.Select(accessFieldExp);
return queryable;
}
@@ -72,6 +95,62 @@ public abstract class EfCoreDataProtectionRepository
await base.DeleteManyAsync(entities, autoSave, cancellationToken);
}
+
+
+ public async override Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default)
+ {
+ CheckAndSetId(entity);
+
+ var dbContext = await GetDbContextAsync();
+
+ var savedEntity = (await dbContext.Set().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 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(
+ this,
+ entityArray,
+ autoSave,
+ GetCancellationToken(cancellationToken)
+ );
+ return;
+ }
+
+ await dbContext.Set().AddRangeAsync(entityArray, cancellationToken);
+
+ if (autoSave)
+ {
+ await dbContext.SaveChangesAsync(cancellationToken);
+ }
+ }
public async override Task UpdateAsync(TEntity entity, bool autoSave = false,
CancellationToken cancellationToken = default)
@@ -88,6 +167,78 @@ public abstract class EfCoreDataProtectionRepository
await base.UpdateManyAsync(entities, autoSave, cancellationToken);
}
+
+ ///
+ /// 创建实体角色数据权限实体
+ ///
+ ///
+ ///
+ ///
+ 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;
+ }
+ ///
+ /// 创建实体组织机构数据权限实体
+ ///
+ ///
+ ///
+ ///
+ 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;
+ }
+ ///
+ /// 持久化实体数据权限
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected async virtual Task PersistenEntityAuthInfoAsync(TDbContext dbContext, TEntity entity, CancellationToken cancellationToken = default)
+ {
+ // 可重写此方法以进行分布式持久化数据权限
+ var entityAuth = dbContext.Set();
+
+ 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));
+ }
+ ///
+ /// 持久化实体数据权限
+ ///
+ ///
+ ///
+ ///
+ ///
+ protected async virtual Task PersistenEntityAuthInfoAsync(TDbContext dbContext, IEnumerable entities, CancellationToken cancellationToken = default)
+ {
+ // 可重写此方法以进行分布式持久化数据权限
+
+ var entityAuth = dbContext.Set();
+ var entityAuths = new List();
+
+ 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 : EfCoreRepository
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs
index 982b7757a..58fae42fc 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs
+++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionModule.cs
@@ -23,6 +23,7 @@ public class AbpDataProtectionModule : AbpModule
{
Configure(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(options =>
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionOptions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionOptions.cs
index 90bd5c877..35031e93d 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionOptions.cs
+++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/AbpDataProtectionOptions.cs
@@ -15,6 +15,10 @@ public class AbpDataProtectionOptions
///
public bool IsEnabled { get; set; }
///
+ /// 数据权限策略
+ ///
+ public IList StrategyContributors { get; }
+ ///
/// 权限主体
///
public IList SubjectContributors { get; }
@@ -46,6 +50,7 @@ public class AbpDataProtectionOptions
{
IsEnabled = true;
SubjectContributors = new List();
+ StrategyContributors = new List();
KeywordContributors = new Dictionary();
OperateContributors = new Dictionary();
DefaultEntityFilters = new Dictionary>();
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessKeywordContributorContext.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessKeywordContributorContext.cs
index 5237a1b62..93e91637a 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessKeywordContributorContext.cs
+++ b/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;
}
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessResourceCacheInvalidator.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessResourceCacheInvalidator.cs
index 58050d9f9..7b54a961e 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessResourceCacheInvalidator.cs
+++ b/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, 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);
+ }
}
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyContributorContext.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyContributorContext.cs
new file mode 100644
index 000000000..8996b1bad
--- /dev/null
+++ b/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;
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyFilterBuildResult.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyFilterBuildResult.cs
new file mode 100644
index 000000000..9af29a5dd
--- /dev/null
+++ b/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
+{
+ public DataAccessStrategy Strategy { get; }
+ public IQueryable Queryable { get; }
+ public DataAccessStrategyFilterBuildResult(
+ DataAccessStrategy strategy,
+ IQueryable queryable)
+ {
+ Strategy = strategy;
+ Queryable = queryable;
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyFilterBuilderBase.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyFilterBuilderBase.cs
new file mode 100644
index 000000000..f7a667826
--- /dev/null
+++ b/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> Build(IQueryable entity, IQueryable entityAuth)
+ where TEntityAuth : DataAuthBase
+ {
+ if (ShouldApplyFilter(typeof(TEntity), DataAccessOperation.Read))
+ {
+
+ var strategyState = await _strategyStateProvider.GetOrNullAsync();
+ if (strategyState != null && strategyState.Strategy != DataAccessStrategy.Custom)
+ {
+ var newQueryable = Build(entity, entityAuth, strategyState);
+
+ return new DataAccessStrategyFilterBuildResult(
+ strategyState.Strategy,
+ newQueryable);
+ }
+ }
+
+ return null;
+ }
+
+ protected virtual bool ShouldApplyFilter(Type entityType, DataAccessOperation operation)
+ {
+ // TODO: 使用一个范围标志来确定当前需要禁用的数据权限操作
+ if (!_dataFilter.IsEnabled())
+ {
+ 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 Build(IQueryable entity, IQueryable entityAuth, DataAccessStrategyState state)
+ where TEntityAuth : DataAuthBase;
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyStateProvider.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessStrategyStateProvider.cs
new file mode 100644
index 000000000..ff2e48344
--- /dev/null
+++ b/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 options,
+ IServiceScopeFactory serviceScopeFactory)
+ {
+ _options = options.Value;
+ _serviceScopeFactory = serviceScopeFactory;
+ }
+
+ public async virtual Task 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;
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAuthBase.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAuthBase.cs
new file mode 100644
index 000000000..0d56e52b9
--- /dev/null
+++ b/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 : Entity, 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;
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptor.cs
index 679e43a7a..e912a1ec7 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectedInterceptor.cs
+++ b/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 options)
+ public DataProtectedInterceptor(
+ IDataFilter dataFilter,
+ IDataAccessScope dataAccessScope,
+ IOptions 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())
{
await invocation.ProceedAsync();
- return;
}
+ return;
}
+
+ var dataProtected = invocation.Method.GetCustomAttribute();
+ 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;
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityPropertyResultBuilder.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityPropertyResultBuilder.cs
index 8689bcd3d..614650ca3 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityPropertyResultBuilder.cs
+++ b/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 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();
- if (disableAttr != null)
+ if (entityType.IsDefined(typeof(DisableDataProtectedAttribute), true))
{
- if (disableAttr.Operation.HasValue && disableAttr.Operation != operation)
- {
- return true;
- }
-
return false;
}
- var dataProtected = entityType.GetCustomAttribute();
-
- if (dataProtected != null && dataProtected.Operation != operation)
+ if (_dataAccessScope.Operations != null && !_dataAccessScope.Operations.Contains(operation))
{
return false;
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityTypeFilterBuilder.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityTypeFilterBuilder.cs
index 1351f63a1..0429ebf1c 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/EntityTypeFilterBuilder.cs
+++ b/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 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();
- if (disableAttr != null)
+ if (entityType.IsDefined(typeof(DisableDataProtectedAttribute), true))
{
- if (disableAttr.Operation.HasValue && disableAttr.Operation != operation)
- {
- return true;
- }
-
return false;
}
- var dataProtected = entityType.GetCustomAttribute();
-
- if (dataProtected != null && dataProtected.Operation != operation)
+ if (_dataAccessScope.Operations != null && !_dataAccessScope.Operations.Contains(operation))
{
return false;
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessKeywordContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessKeywordContributor.cs
index aec82e52c..649d919b5 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessKeywordContributor.cs
+++ b/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);
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyContributor.cs
new file mode 100644
index 000000000..6561518e8
--- /dev/null
+++ b/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 GetOrNullAsync(DataAccessStrategyContributorContext context);
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyFilterBuilder.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyFilterBuilder.cs
new file mode 100644
index 000000000..eaa49fc6a
--- /dev/null
+++ b/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;
+
+///
+/// 数据权限策略过滤器
+///
+public interface IDataAccessStrategyFilterBuilder
+{
+ Task> Build(IQueryable entity, IQueryable entityAuth)
+ where TEntityAuth : DataAuthBase;
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyStateProvider.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessStrategyStateProvider.cs
new file mode 100644
index 000000000..3568d1a0a
--- /dev/null
+++ b/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 GetOrNullAsync();
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/InMemoryDataProtectedResourceStore.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/InMemoryDataProtectedResourceStore.cs
deleted file mode 100644
index 39b1c3149..000000000
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/InMemoryDataProtectedResourceStore.cs
+++ /dev/null
@@ -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 _cache = new ConcurrentDictionary();
- 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 GetAsync(string subjectName, string subjectId, string entityTypeFullName, DataAccessOperation operation)
- {
- return Task.FromResult(Get(subjectName, subjectId, entityTypeFullName, operation));
- }
-}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Keywords/DataAccessCurrentUserContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Keywords/DataAccessCurrentUserContributor.cs
index 296310ff1..507a7ef23 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Keywords/DataAccessCurrentUserContributor.cs
+++ b/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;
+///
+/// 适用于过滤当前用户数据
+///
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();
- 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)
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataAccessStrategyStateCacheItem.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataAccessStrategyStateCacheItem.cs
new file mode 100644
index 000000000..0d97bde0c
--- /dev/null
+++ b/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}";
+ ///
+ /// 权限主体
+ ///
+ public string SubjectName { get; set; }
+
+ ///
+ /// 权限主体标识
+ ///
+ public string SubjectId { get; set; }
+
+ ///
+ /// 权限策略
+ ///
+ 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);
+ }
+}
diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCache.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceCache.cs
similarity index 95%
rename from aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCache.cs
rename to aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceCache.cs
index 56782fc79..b5a160d97 100644
--- a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCache.cs
+++ b/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 _cache;
diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItem.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceCacheItem.cs
similarity index 92%
rename from aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItem.cs
rename to aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceCacheItem.cs
index 925b0610a..6a8f20fa8 100644
--- a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheItem.cs
+++ b/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}";
diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheStore.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceStore.cs
similarity index 79%
rename from aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheStore.cs
rename to aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedResourceStore.cs
index 1e1a87eec..56d776961 100644
--- a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/DataProtectedResourceCacheStore.cs
+++ b/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;
}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedStrategyStateCache.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedStrategyStateCache.cs
new file mode 100644
index 000000000..dc34b2f1c
--- /dev/null
+++ b/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 _cache;
+
+ public DataProtectedStrategyStateCache(IDistributedCache cache)
+ {
+ _cache = cache;
+ }
+
+ public async virtual Task 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());
+ }
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedStrategyStateStore.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/DataProtectedStrategyStateStore.cs
new file mode 100644
index 000000000..ade9b168e
--- /dev/null
+++ b/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 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);
+ }
+}
diff --git a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IDataProtectedResourceCache.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedResourceCache.cs
similarity index 94%
rename from aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IDataProtectedResourceCache.cs
rename to aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedResourceCache.cs
index 2aeaf6c41..8257bb54f 100644
--- a/aspnet-core/modules/data-protection/LINGYUN.Abp.DataProtectionManagement.Domain/LINGYUN/Abp/DataProtectionManagement/IDataProtectedResourceCache.cs
+++ b/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
{
///
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectedResourceStore.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedResourceStore.cs
similarity index 87%
rename from aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectedResourceStore.cs
rename to aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedResourceStore.cs
index b01b4f2c1..0de7bbd87 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectedResourceStore.cs
+++ b/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);
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedStrategyStateCache.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedStrategyStateCache.cs
new file mode 100644
index 000000000..af3db1321
--- /dev/null
+++ b/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 GetAsync(string subjectName, string subjectId);
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedStrategyStateStore.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Stores/IDataProtectedStrategyStateStore.cs
new file mode 100644
index 000000000..bcdec11fb
--- /dev/null
+++ b/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 GetOrNullAsync(string subjectName, string subjectId);
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessClientIdContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessClientIdContributor.cs
index c63992adf..632878484 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessClientIdContributor.cs
+++ b/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;
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessOrganizationUnitContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessOrganizationUnitContributor.cs
index 82ecf6d81..8031f1adb 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessOrganizationUnitContributor.cs
+++ b/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;
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessRoleNameContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessRoleNameContributor.cs
index 89712396b..8c00437cd 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessRoleNameContributor.cs
+++ b/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;
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessStrategyRoleNameContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessStrategyRoleNameContributor.cs
new file mode 100644
index 000000000..2f479b7de
--- /dev/null
+++ b/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;
+
+///
+/// 角色数据权限策略
+///
+public class DataAccessStrategyRoleNameContributor : IDataAccessStrategyContributor
+{
+ public string Name => RolePermissionValueProvider.ProviderName;
+
+ public async virtual Task GetOrNullAsync(DataAccessStrategyContributorContext context)
+ {
+ var states = new List();
+ var currentUser = context.ServiceProvider.GetRequiredService();
+ if (!currentUser.IsAuthenticated)
+ {
+ return null;
+ }
+ var store = context.ServiceProvider.GetRequiredService();
+ 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();
+ }
+}
diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessUserIdContributor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessUserIdContributor.cs
index 834d682ff..48e4986b4 100644
--- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/Subjects/DataAccessUserIdContributor.cs
+++ b/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;
diff --git a/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250402083655_Upgrade-Abp-Framework-To-9.1.1.Designer.cs b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250402083655_Upgrade-Abp-Framework-To-9.1.1.Designer.cs
new file mode 100644
index 000000000..265b26dd2
--- /dev/null
+++ b/aspnet-core/migrations/LY.MicroService.Applications.Single.EntityFrameworkCore.MySql/Migrations/20250402083655_Upgrade-Abp-Framework-To-9.1.1.Designer.cs
@@ -0,0 +1,5328 @@
+//
+using System;
+using LY.MicroService.Applications.Single.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Volo.Abp.EntityFrameworkCore;
+
+#nullable disable
+
+namespace LY.MicroService.Applications.Single.EntityFrameworkCore.MySql.Migrations
+{
+ [DbContext(typeof(SingleMigrationsDbContext))]
+ [Migration("20250402083655_Upgrade-Abp-Framework-To-9.1.1")]
+ partial class UpgradeAbpFrameworkTo911
+ {
+ ///
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("_Abp_DatabaseProvider", EfCoreDatabaseProvider.MySql)
+ .HasAnnotation("ProductVersion", "9.0.2")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder);
+
+ modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityEnumInfo", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("varchar(128)")
+ .HasColumnName("DisplayName");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)")
+ .HasColumnName("Name");
+
+ b.Property("PropertyInfoId")
+ .HasColumnType("char(36)");
+
+ b.Property("Value")
+ .IsRequired()
+ .HasMaxLength(10)
+ .HasColumnType("varchar(10)")
+ .HasColumnName("Value");
+
+ b.HasKey("Id");
+
+ b.HasIndex("PropertyInfoId", "Name");
+
+ b.ToTable("AbpAuthEntityEnums", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityPropertyInfo", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("varchar(128)")
+ .HasColumnName("DisplayName");
+
+ b.Property("JavaScriptType")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)")
+ .HasColumnName("JavaScriptType");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)")
+ .HasColumnName("Name");
+
+ b.Property("TypeFullName")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)")
+ .HasColumnName("TypeFullName");
+
+ b.Property("TypeInfoId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TypeInfoId", "TypeFullName");
+
+ b.ToTable("AbpAuthEntityProperties", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.EntityTypeInfo", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("char(36)")
+ .HasColumnName("CreatorId");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("varchar(128)")
+ .HasColumnName("DisplayName");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsAuditEnabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("char(36)")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)")
+ .HasColumnName("Name");
+
+ b.Property("TypeFullName")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)")
+ .HasColumnName("TypeFullName");
+
+ b.HasKey("Id");
+
+ b.HasIndex("TypeFullName");
+
+ b.ToTable("AbpAuthEntitites", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.OrganizationUnitEntityRule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("AccessedProperties")
+ .HasMaxLength(512)
+ .HasColumnType("varchar(512)")
+ .HasColumnName("AccessedProperties");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("char(36)")
+ .HasColumnName("CreatorId");
+
+ b.Property("EntityTypeFullName")
+ .HasColumnType("longtext");
+
+ b.Property("EntityTypeId")
+ .HasColumnType("char(36)");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("FilterGroup")
+ .HasColumnType("longtext")
+ .HasColumnName("FilterGroup");
+
+ b.Property("IsEnabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("char(36)")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Operation")
+ .HasColumnType("int");
+
+ b.Property("OrgCode")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("varchar(128)")
+ .HasColumnName("OrgCode");
+
+ b.Property("OrgId")
+ .HasColumnType("char(36)");
+
+ b.Property("TenantId")
+ .HasColumnType("char(36)")
+ .HasColumnName("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EntityTypeId");
+
+ b.ToTable("AbpAuthOrganizationUnitEntityRules", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.DataProtectionManagement.RoleEntityRule", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("AccessedProperties")
+ .HasMaxLength(512)
+ .HasColumnType("varchar(512)")
+ .HasColumnName("AccessedProperties");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("char(36)")
+ .HasColumnName("CreatorId");
+
+ b.Property("EntityTypeFullName")
+ .HasColumnType("longtext");
+
+ b.Property("EntityTypeId")
+ .HasColumnType("char(36)");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("FilterGroup")
+ .HasColumnType("longtext")
+ .HasColumnName("FilterGroup");
+
+ b.Property("IsEnabled")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("char(36)")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Operation")
+ .HasColumnType("int");
+
+ b.Property("RoleId")
+ .HasColumnType("char(36)");
+
+ b.Property("RoleName")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)")
+ .HasColumnName("RoleName");
+
+ b.Property("TenantId")
+ .HasColumnType("char(36)")
+ .HasColumnName("TenantId");
+
+ b.HasKey("Id");
+
+ b.HasIndex("EntityTypeId");
+
+ b.ToTable("AbpAuthRoleEntityRules", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Demo.Authors.Author", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("BirthDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("char(36)")
+ .HasColumnName("CreatorId");
+
+ b.Property("DeleterId")
+ .HasColumnType("char(36)")
+ .HasColumnName("DeleterId");
+
+ b.Property("DeletionTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("DeletionTime");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("IsDeleted")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("tinyint(1)")
+ .HasDefaultValue(false)
+ .HasColumnName("IsDeleted");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("char(36)")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)");
+
+ b.Property("ShortBio")
+ .HasColumnType("longtext");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name");
+
+ b.ToTable("Demo_Authors", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Demo.Books.Book", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("AuthorId")
+ .HasColumnType("char(36)");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("char(36)")
+ .HasColumnName("CreatorId");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("char(36)")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(128)
+ .HasColumnType("varchar(128)");
+
+ b.Property("Price")
+ .HasColumnType("float");
+
+ b.Property("PublishDate")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Type")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.HasIndex("AuthorId");
+
+ b.ToTable("Demo_Books", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprInfo", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("Data")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasColumnName("Data");
+
+ b.Property("Provider")
+ .IsRequired()
+ .HasMaxLength(256)
+ .HasColumnType("varchar(256)")
+ .HasColumnName("Provider");
+
+ b.Property("RequestId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("RequestId");
+
+ b.ToTable("AbpGdprInfos", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.Gdpr.GdprRequest", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("ConcurrencyStamp")
+ .IsConcurrencyToken()
+ .IsRequired()
+ .HasMaxLength(40)
+ .HasColumnType("varchar(40)")
+ .HasColumnName("ConcurrencyStamp");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("CreationTime");
+
+ b.Property("ExtraProperties")
+ .IsRequired()
+ .HasColumnType("longtext")
+ .HasColumnName("ExtraProperties");
+
+ b.Property("ReadyTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("UserId")
+ .HasColumnType("char(36)");
+
+ b.HasKey("Id");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("AbpGdprRequests", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Language", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("char(36)")
+ .HasColumnName("CreatorId");
+
+ b.Property("CultureName")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)")
+ .HasColumnName("CultureName");
+
+ b.Property("DisplayName")
+ .IsRequired()
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)")
+ .HasColumnName("DisplayName");
+
+ b.Property("Enable")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("tinyint(1)")
+ .HasDefaultValue(true);
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("char(36)")
+ .HasColumnName("LastModifierId");
+
+ b.Property("TwoLetterISOLanguageName")
+ .HasMaxLength(30)
+ .HasColumnType("varchar(30)")
+ .HasColumnName("TwoLetterISOLanguageName");
+
+ b.Property("UiCultureName")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)")
+ .HasColumnName("UiCultureName");
+
+ b.HasKey("Id");
+
+ b.HasIndex("CultureName");
+
+ b.ToTable("AbpLocalizationLanguages", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Resource", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("char(36)");
+
+ b.Property("CreationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("CreationTime");
+
+ b.Property("CreatorId")
+ .HasColumnType("char(36)")
+ .HasColumnName("CreatorId");
+
+ b.Property("DefaultCultureName")
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)")
+ .HasColumnName("DefaultCultureName");
+
+ b.Property("Description")
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)")
+ .HasColumnName("Description");
+
+ b.Property("DisplayName")
+ .HasMaxLength(64)
+ .HasColumnType("varchar(64)")
+ .HasColumnName("DisplayName");
+
+ b.Property("Enable")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("tinyint(1)")
+ .HasDefaultValue(true);
+
+ b.Property("LastModificationTime")
+ .HasColumnType("datetime(6)")
+ .HasColumnName("LastModificationTime");
+
+ b.Property("LastModifierId")
+ .HasColumnType("char(36)")
+ .HasColumnName("LastModifierId");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(50)
+ .HasColumnType("varchar(50)")
+ .HasColumnName("Name");
+
+ b.HasKey("Id");
+
+ b.HasIndex("Name");
+
+ b.ToTable("AbpLocalizationResources", (string)null);
+ });
+
+ modelBuilder.Entity("LINGYUN.Abp.LocalizationManagement.Text", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id"));
+
+ b.Property("CultureName")
+ .IsRequired()
+ .HasMaxLength(20)
+ .HasColumnType("varchar(20)")
+ .HasColumnName("CultureName");
+
+ b.Property("Key")
+ .IsRequired()
+ .HasMaxLength(512)
+ .HasColumnType("varchar(512)")
+ .HasColumnName("Key");
+
+ b.Property("ResourceName")
+ .HasColumnType("longtext");
+
+ b.Property