diff --git a/aspnet-core/LINGYUN.MicroService.All.sln b/aspnet-core/LINGYUN.MicroService.All.sln index f960482fe..5cb576aa5 100644 --- a/aspnet-core/LINGYUN.MicroService.All.sln +++ b/aspnet-core/LINGYUN.MicroService.All.sln @@ -702,6 +702,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dynamic.Queryab EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Dynamic.Queryable.HttpApi", "framework\dynamic-queryable\LINGYUN.Abp.Dynamic.Queryable.HttpApi\LINGYUN.Abp.Dynamic.Queryable.HttpApi.csproj", "{014A9583-0EAA-48A4-ACBE-07DC88159E13}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.DataProtection.Tests", "tests\LINGYUN.Abp.DataProtection.Tests\LINGYUN.Abp.DataProtection.Tests.csproj", "{AAC0C407-B4B9-4E90-99FC-2D793AC229D9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1784,6 +1786,10 @@ Global {014A9583-0EAA-48A4-ACBE-07DC88159E13}.Debug|Any CPU.Build.0 = Debug|Any CPU {014A9583-0EAA-48A4-ACBE-07DC88159E13}.Release|Any CPU.ActiveCfg = Release|Any CPU {014A9583-0EAA-48A4-ACBE-07DC88159E13}.Release|Any CPU.Build.0 = Release|Any CPU + {AAC0C407-B4B9-4E90-99FC-2D793AC229D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AAC0C407-B4B9-4E90-99FC-2D793AC229D9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AAC0C407-B4B9-4E90-99FC-2D793AC229D9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AAC0C407-B4B9-4E90-99FC-2D793AC229D9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2123,6 +2129,7 @@ Global {B6D4AADE-3ABA-45E6-9916-2F8798412549} = {4FAE314C-36CB-4E3F-85B7-41D0A428B37D} {86E85013-7C71-4770-9323-18897A64F5B2} = {4FAE314C-36CB-4E3F-85B7-41D0A428B37D} {014A9583-0EAA-48A4-ACBE-07DC88159E13} = {4FAE314C-36CB-4E3F-85B7-41D0A428B37D} + {AAC0C407-B4B9-4E90-99FC-2D793AC229D9} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718} 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 98dfb957a..1c8e0b466 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 @@ -1,14 +1,145 @@ using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.ChangeTracking; +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using Volo.Abp.Domain.Entities; using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.MultiTenancy; +using Volo.Abp.Uow; +using Volo.Abp.Users; namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore { - public class AbpDataProtectionDbContext : AbpDbContext - where TDbContext : DbContext + public class AbpDataProtectionDbContext : AbpDbContext { + protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetService(); + + protected virtual bool IsDataAccessFilterEnabled => DataFilter?.IsEnabled() ?? false; + public AbpDataProtectionDbContext( - DbContextOptions options) : base(options) + DbContextOptions options) : base(options) + { + } + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + base.OnModelCreating(modelBuilder); + + foreach (var entityType in modelBuilder.Model.GetEntityTypes()) + { + if (typeof(IHasDataAccess).IsAssignableFrom(entityType.ClrType)) + { + modelBuilder.Entity(entityType.ClrType) + .OwnsOne(entityType.ClrType.FullName, nameof(IHasDataAccess.Owner), ownedNavigationBuilder => + { + ownedNavigationBuilder.ToJson(); + }); + } + } + } + + protected override void ApplyAbpConceptsForAddedEntity(EntityEntry entry) { + base.ApplyAbpConceptsForAddedEntity(entry); + if (CurrentUser.IsAuthenticated) + { + if (entry is IHasDataAccess entity) + { + ProtectedEntityHelper.TrySetOwner( + entity, + () => new DataAccessOwner( + CurrentUser.Id, + CurrentUser.Roles, + CurrentUser.FindOrganizationUnits().Select(ou => ou.ToString()).ToArray())); + } + } + } + + protected virtual DataAccessRuleInfo AccessRuleInfo => UnitOfWorkManager.Current.GetAccessRuleInfo(); + + protected override void HandlePropertiesBeforeSave() + { + foreach (var item in ChangeTracker.Entries().ToList()) + { + HandleExtraPropertiesOnSave(item); + HandleCheckPropertiesOnSave(item); + if (item.State.IsIn(EntityState.Modified, EntityState.Deleted)) + { + UpdateConcurrencyStamp(item); + } + } + } + + protected virtual void HandleCheckPropertiesOnSave(EntityEntry entry) + { + // 仅当启用过滤器时检查 + if (IsDataAccessFilterEnabled) + { + var entityAccessRules = AccessRuleInfo?.Rules.Where(r => r.EntityTypeFullName == entry.Metadata.ClrType.FullName); + if (entityAccessRules != null) + { + if (entry.State.IsIn(EntityState.Modified, EntityState.Added, EntityState.Deleted)) + { + var entityAccessRule = entityAccessRules.FirstOrDefault(r => r.Operation.IsIn(DataAccessOperation.Write, DataAccessOperation.Delete)); + if (entityAccessRule != null) + { + if (entityAccessRule.Fileds.Count != 0) + { + var notAccessProps = entry.Properties.Where(p => !entityAccessRule.Fileds.Any(f => f.Field == p.Metadata.Name)); + if (notAccessProps != null) + { + foreach (var property in notAccessProps) + { + // 无字段权限不做变更 + property.CurrentValue = property.OriginalValue; + } + } + } + } + else + { + // 无实体变更权限不做修改 + entry.State = EntityState.Unchanged; + } + } + } + } + } + + protected override Expression> CreateFilterExpression() + { + var expression = base.CreateFilterExpression(); + + if (typeof(IHasDataAccess).IsAssignableFrom(typeof(TEntity))) + { + Expression> expression2 = (TEntity e) => !IsDataAccessFilterEnabled || CreateFilterExpression(e, AccessRuleInfo); + expression = (Expression>)((expression == null) ? ((LambdaExpression)expression2) : ((LambdaExpression)QueryFilterExpressionHelper.CombineExpressions(expression, expression2))); + } + + return expression; + } + + protected static bool CreateFilterExpression(TEntity entity, DataAccessRuleInfo accessRuleInfo) + { + if (accessRuleInfo == null) + { + return true; + } + + if (!accessRuleInfo.Rules.Any(r => r.EntityTypeFullName == typeof(TEntity).FullName)) + { + return false; + } + + if (entity is not IHasDataAccess accessEntity) + { + return true; + } + + // TODO: 需要完成详细的过滤条件 + return false; } } } diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionQueryExpressionInterceptor.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionQueryExpressionInterceptor.cs index 7d45209ae..f5bf7664d 100644 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionQueryExpressionInterceptor.cs +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/DataProtectionQueryExpressionInterceptor.cs @@ -1,47 +1,85 @@ -using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; +using System.Reflection.Metadata; using System.Text; using System.Threading.Tasks; using Volo.Abp.Data; +using Volo.Abp.Domain.Entities; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.Users; namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore; public class DataProtectionQueryExpressionInterceptor : IQueryExpressionInterceptor { public Expression QueryCompilationStarting(Expression queryExpression, QueryExpressionEventData eventData) { - return new DataProtectionExpressionVisitor().Visit(queryExpression); + var dataFilter = eventData.Context.GetService(); + var dbContextProvider = eventData.Context.GetService>(); + return new DataProtectionExpressionVisitor(dataFilter, dbContextProvider).Visit(queryExpression); } public class DataProtectionExpressionVisitor : ExpressionVisitor { private readonly static MethodInfo WhereMethodInfo = typeof(Queryable).GetMethod(nameof(Queryable.Where)); + + private readonly IDataFilter _dataFilter; + private readonly ICurrentUser _currentUser; + private readonly IDbContextProvider _dbContextProvider; + + public DataProtectionExpressionVisitor( + IDataFilter dataFilter, + IDbContextProvider dbContextProvider) + { + _dataFilter = dataFilter; + _dbContextProvider = dbContextProvider; + } protected override Expression VisitMethodCall(MethodCallExpression node) { - //if (_dataFilter.IsEnabled()) - //{ - // var methodInfo = node!.Method; - // if (methodInfo.DeclaringType == typeof(Queryable) - // && methodInfo.Name == nameof(Queryable.Select) - // && methodInfo.GetParameters().Length == 2) - // { - // var sourceType = node.Type.GetGenericArguments()[0]; - // var lambdaExpression = (LambdaExpression)((UnaryExpression)node.Arguments[1]).Operand; - // var entityParameterExpression = lambdaExpression.Parameters[0]; - // var test = Expression.Call( - // method: WhereMethodInfo.MakeGenericMethod(sourceType, typeof(bool)), - // arg0: base.VisitMethodCall(node), - // arg1: Expression.Lambda(typeof(Func<,>).MakeGenericType(entityParameterExpression.Type, typeof(bool)), - // Expression.Property(entityParameterExpression, nameof(IDataProtection.Owner)), - // true)); - // return test; - // } - //} + if (_dataFilter.IsEnabled()) + { + var methodInfo = node!.Method; + if (methodInfo.DeclaringType == typeof(Queryable) + && methodInfo.Name == nameof(Queryable.Select) + && methodInfo.GetParameters().Length == 2) + { + var sourceType = node.Type.GetGenericArguments()[0]; + var lambdaExpression = (LambdaExpression)((UnaryExpression)node.Arguments[1]).Operand; + var entityParameterExpression = lambdaExpression.Parameters[0]; + + var rules = _currentUser.Roles; + var ous = _currentUser.FindOrganizationUnits(); + + var ownerParamter = Expression.PropertyOrField(entityParameterExpression, nameof(IHasDataAccess.Owner)); + + + if (typeof(IEntity).IsAssignableFrom(sourceType)) + { + // Join params[0] + // node + + + + + var test = Expression.Call( + method: WhereMethodInfo.MakeGenericMethod(sourceType, typeof(bool)), + arg0: base.VisitMethodCall(node), + arg1: Expression.Lambda( + typeof(Func<,>).MakeGenericType(entityParameterExpression.Type, typeof(bool)), + Expression.Property(entityParameterExpression, nameof(IHasDataAccess.Owner)), + true)); + return test; + } + + } + } return base.VisitMethodCall(node); } } diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepositoryBase.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepositoryBase.cs deleted file mode 100644 index 1a4e23ce5..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/EfCoreDataProtectionRepositoryBase.cs +++ /dev/null @@ -1,297 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Domain.Entities; -using Volo.Abp.Domain.Repositories.EntityFrameworkCore; -using Volo.Abp.EntityFrameworkCore; -using Volo.Abp.Users; - -namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore -{ - /// - /// 受保护的资源仓储接口需要继承此接口,否则需要自行实现过滤器 - /// - /// - /// - /// - public abstract class EfCoreDataProtectionRepositoryBase : EfCoreRepository - where TEntity : class, IEntity, IDataProtection - where TDbContext: IEfCoreDbContext - { - protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetService(); - protected IDataProtectdChecker DataProtectdChecker => LazyServiceProvider.LazyGetService(); - protected EfCoreDataProtectionRepositoryBase( - IDbContextProvider dbContextProvider) - : base(dbContextProvider) - { - } - - public override async Task InsertAsync(TEntity entity, bool autoSave = false, CancellationToken cancellationToken = default) - { - if (CurrentUser.IsAuthenticated && - entity is IDataProtection protectedEntity) - { - ProtectedEntityHelper.TrySetOwner( - protectedEntity, - () => string.Join(",", CurrentUser.UserName, CurrentUser.Roles.JoinAsString(","))); - } - - return await base.InsertAsync(entity, autoSave, cancellationToken); - } - - public override async Task InsertManyAsync(IEnumerable entities, bool autoSave = false, CancellationToken cancellationToken = default) - { - if (CurrentUser.IsAuthenticated && - typeof(IDataProtection).IsAssignableFrom(typeof(TEntity))) - { - foreach (var entity in entities) - { - ProtectedEntityHelper.TrySetOwner( - entity, - () => string.Join(",", CurrentUser.UserName, CurrentUser.Roles.JoinAsString(","))); - } - } - - await base.InsertManyAsync(entities, autoSave, cancellationToken); - } - - public override async Task> GetListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) - { - return includeDetails - ? await(await WithDetailsAsync(ProtectBehavior.Query)).ToListAsync(GetCancellationToken(cancellationToken)) - : await(await GetQueryableAsync(ProtectBehavior.Query)).ToListAsync(GetCancellationToken(cancellationToken)); - } - - public override async Task FindAsync(TKey id, bool includeDetails = true, CancellationToken cancellationToken = default) - { - return includeDetails - ? await(await WithDetailsAsync(ProtectBehavior.Query)).OrderBy(e => e.Id).FirstOrDefaultAsync(e => e.Id.Equals(id), GetCancellationToken(cancellationToken)) - : await(await GetQueryableAsync(ProtectBehavior.Query)).OrderBy(e => e.Id).FirstOrDefaultAsync(e => e.Id.Equals(id), GetCancellationToken(cancellationToken)); - } - - public override async Task> GetListAsync( - Expression> predicate, - bool includeDetails = false, - CancellationToken cancellationToken = default) - { - return includeDetails - ? await (await WithDetailsAsync(ProtectBehavior.Query)).Where(predicate).ToListAsync(GetCancellationToken(cancellationToken)) - : await (await GetQueryableAsync(ProtectBehavior.Query)).Where(predicate).ToListAsync(GetCancellationToken(cancellationToken)); - } - - public override async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default) - { - var queryable = await GetQueryableAsync(ProtectBehavior.Delete); - var entity = await queryable - .FirstOrDefaultAsync(e => e.Id.Equals(id), GetCancellationToken(cancellationToken)); - if (entity == null) - { - return; - } - await DeleteAsync(entity, autoSave, cancellationToken); - } - - public override async Task DeleteManyAsync(IEnumerable ids, bool autoSave = false, CancellationToken cancellationToken = default) - { - var queryable = await GetQueryableAsync(ProtectBehavior.Delete); - - var entities = await queryable.Where(x => ids.Contains(x.Id)).ToListAsync(cancellationToken); - - await DeleteManyAsync(entities, autoSave, cancellationToken); - } - - public override async Task DeleteAsync( - Expression> predicate, - bool autoSave = false, - CancellationToken cancellationToken = default) - { - var queryable = await GetQueryableAsync(ProtectBehavior.Delete); - - var entities = await queryable.Where(predicate).ToListAsync(cancellationToken); - - await DeleteManyAsync(entities, autoSave, cancellationToken); - } - protected async virtual Task> WithDetailsAsync(ProtectBehavior behavior = ProtectBehavior.All) - { - if (typeof(IDataProtection).IsAssignableFrom(typeof(TEntity))) - { - var result = await DataProtectdChecker.IsGrantedAsync(behavior); - if (!result.Succeeded) - { - var queryable = await base.GetQueryableAsync(); - return queryable.Where((t) => false); - } - - return await WithDetailsAsync(result); - } - - return await base.WithDetailsAsync(); - } - protected async virtual Task> WithDetailsAsync(ResourceGrantedResult resourceGranted) - { - if (AbpEntityOptions.DefaultWithDetailsFunc == null) - { - return await GetQueryableAsync(resourceGranted); - } - - return AbpEntityOptions.DefaultWithDetailsFunc(await GetQueryableAsync(resourceGranted)); - } - protected async virtual Task> GetQueryableAsync(ProtectBehavior behavior = ProtectBehavior.All) - { - if (typeof(IDataProtection).IsAssignableFrom(typeof(TEntity))) - { - var result = await DataProtectdChecker.IsGrantedAsync(behavior); - if (!result.Succeeded) - { - var queryable = await base.GetQueryableAsync(); - return queryable.Where((t) => false); - } - - return await GetQueryableAsync(result); - } - - return await base.GetQueryableAsync(); - } - protected async virtual Task> GetQueryableAsync(ResourceGrantedResult resourceGranted) - { - var queryable = await base.GetQueryableAsync(); - if (!resourceGranted.Succeeded) - { - // 无资源访问权限, 不返回结果 - return queryable.Where((t) => false); - } - // 资源过滤,用户是否有对某个资源的访问权限 - // 方案1、Resource.Owner In ("user1", "user2", "role1", "role2", "organization1", "...") 独立模块,业务增加Owner字段 - // 方案2、Select R.* From Resource R Inner Join Protect T On T.Visitor = R.Owner Where T.Resource = 'Resource' 业务侵入,增加Protect表 - queryable = FilterResource(queryable, resourceGranted.Resource); - // 对于可访问资源的进一步动态规则过滤 1 == 1 And Resource.Field1 = 'allow' And Resource.Field2 >= 100 And Resource.Field2 <= 200 - queryable = FilterFieldRule(queryable, resourceGranted.Rules); - // 对于资源可访问字段过滤 Select Resource.Field1, Resource.Field2, Resource.Field3 - queryable = FilterFieldReturn(queryable, resourceGranted.Fields); - - return queryable; - } - - protected virtual IQueryable FilterResource(IQueryable queryable, ProtectedResource resource) - where T : IDataProtection - { - ParameterExpression pe = Expression.Parameter(typeof(T)); - - // 检查资源的可访问者 - // any: 内置常量,允许访问所有资源 - if (!resource.Visitor.IsNullOrWhiteSpace() || !resource.Visitor.Contains("any")) - { - // 过滤允许的资源访问者 - // 方案一:模块之间独立,传递当前访问者即可 - // Select * From Resource As R Where R.Owner LIKE ('visitor1', 'visitorRole1') - var ownerExp = Expression.PropertyOrField(pe, nameof(IDataProtection.Owner)); - var visities = resource.Visitor.Split(','); - Expression visitorExpr = null; - foreach (var visitor in visities) - { - visitorExpr = visitorExpr == null - ? Expression.Call( - ownerExp, - typeof(string).GetMethod(nameof(string.Contains), new Type[] { typeof(string) }), - Expression.Constant(visitor, ownerExp.Type)) - : Expression.Or( - visitorExpr, - Expression.Call( - ownerExp, - typeof(string).GetMethod(nameof(string.Contains), new Type[] { typeof(string) }), - Expression.Constant(visitor, ownerExp.Type))); - } - - // 方案二:节省网络带宽,快速查询 - // Select R.* From Resource As R - // Inner Join Protect As P On P.Resource = 'Resource' - // Where 1 == 1 - // And P.Behavior = ProtectBehavior.Query - // And ((P.Visitor = 'visitor1') Or (P.Visitor = 'visitorRole1') Or (P.Visitor = 'visitorRole2')) - queryable = queryable.Where(Expression.Lambda>(visitorExpr, pe)); - } - - return queryable; - } - - protected virtual IQueryable FilterFieldRule(IQueryable queryable, IEnumerable rules) - where T : IDataProtection - { - ParameterExpression pe = Expression.Parameter(typeof(T)); - - // 默认未指定访问规则 - // 则可访问所有允许的资源 - if (rules.Any()) - { - Expression> where = PredicateBuilder.New((t) => true); - foreach (var fieldRule in rules) - { - var memberExp = Expression.PropertyOrField(pe, fieldRule.Field); - Expression memberCondition = null; - memberCondition = fieldRule.Operator switch - { - // LIKE - ExpressionType.Contains => Expression.Call( - memberExp, - typeof(string).GetMethod(nameof(string.Contains), new Type[] { typeof(string) }), - Expression.Constant(fieldRule.Value, memberExp.Type)), - // == - ExpressionType.Equal => Expression.Equal(memberExp, Expression.Constant(fieldRule.Value, memberExp.Type)), - // < - ExpressionType.LessThan => Expression.LessThan(memberExp, Expression.Constant(fieldRule.Value, memberExp.Type)), - // <= - ExpressionType.LessThanOrEqual => Expression.LessThanOrEqual(memberExp, Expression.Constant(fieldRule.Value, memberExp.Type)), - // > - ExpressionType.GreaterThan => Expression.GreaterThan(memberExp, Expression.Constant(fieldRule.Value, memberExp.Type)), - // >= - ExpressionType.GreaterThanOrEqual => Expression.GreaterThanOrEqual(memberExp, Expression.Constant(fieldRule.Value, memberExp.Type)), - // 其他操作符未引入 - _ => throw new NotSupportedException($"Dynamic rules do not support operator: {fieldRule.Operator}"), - }; - switch (fieldRule.Logic) - { - case PredicateOperator.And: - where = where.And(Expression.Lambda>(memberCondition, pe)); - break; - case PredicateOperator.Or: - where = where.Or(Expression.Lambda>(memberCondition, pe)); - break; - } - } - queryable = queryable.Where(where); - } - - return queryable; - } - - protected virtual IQueryable FilterFieldReturn(IQueryable queryable, IEnumerable fields) - { - // 默认未指定可访问字段则返回所有字段 - if (fields.Any()) - { - ParameterExpression pe = Expression.Parameter(typeof(T)); - Type queryableResultType = typeof(T); - NewExpression ne = Expression.New(queryableResultType); - List members = new List(); - - foreach (var field in fields) - { - var fieldProp = queryableResultType.GetProperty(field.Field); - var meField = Expression.MakeMemberAccess(pe, fieldProp); - members.Add(Expression.Bind(fieldProp, meField)); - } - - var mie = Expression.MemberInit(ne, members); - Expression> personSelectExpression = Expression.Lambda>(mie, pe); - - queryable = queryable.Select(personSelectExpression); - } - - return queryable; - } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/ProtectedEntityHelper.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/ProtectedEntityHelper.cs index e0a49e52e..ef6e8ed94 100644 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/ProtectedEntityHelper.cs +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection.EntityFrameworkCore/LINGYUN/Abp/DataProtection/EntityFrameworkCore/ProtectedEntityHelper.cs @@ -6,8 +6,8 @@ namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore public static class ProtectedEntityHelper { public static void TrySetOwner( - IDataProtection protectedEntity, - Func ownerFactory) + IHasDataAccess protectedEntity, + Func ownerFactory) { ObjectHelper.TrySetProperty( protectedEntity, diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN.Abp.DataProtection.csproj b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN.Abp.DataProtection.csproj index 238141cce..d012adbc6 100644 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN.Abp.DataProtection.csproj +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN.Abp.DataProtection.csproj @@ -9,7 +9,11 @@ - + + + + + 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 acf139c93..130460543 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 @@ -1,11 +1,10 @@ -using Volo.Abp.Modularity; -using Volo.Abp.Threading; +using Volo.Abp.Domain; +using Volo.Abp.Modularity; -namespace LINGYUN.Abp.DataProtection +namespace LINGYUN.Abp.DataProtection; + +[DependsOn( + typeof(AbpDddDomainModule))] +public class AbpDataProtectionModule : AbpModule { - [DependsOn( - typeof(AbpThreadingModule))] - public class AbpDataProtectionModule : AbpModule - { - } } diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessCacheItem.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessCacheItem.cs new file mode 100644 index 000000000..99f43c29c --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessCacheItem.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.DataProtection; +public class DataAccessCacheItem +{ + /// + /// 实体类型全名 + /// + public string EntityTypeFullName { get; set; } + /// + /// 数据访问操作 + /// + public DataAccessOperation Operation { get; set; } + /// + /// 数据访问角色 + /// + public DataAccessRole Role { get; set; } + /// + /// 资源访问者 + /// + public string Visitor { get; set; } + /// + /// 字段访问控制 + /// + public List Fileds { get; set; } + /// + /// 自定义表达式 + /// + public List Expressions { get; set; } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessEntityRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessEntityRule.cs new file mode 100644 index 000000000..e786386c5 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessEntityRule.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据访问实体控制 +/// +public class DataAccessEntityRule +{ + +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessExpressionRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessExpressionRule.cs new file mode 100644 index 000000000..e4665ab8c --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessExpressionRule.cs @@ -0,0 +1,11 @@ +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据访问控制规则:自定义表达式 +/// +public class DataAccessExpressionRule +{ + /// + /// 表达式 + /// + public virtual string Expression { get; protected set; } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessFiledRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessFiledRule.cs new file mode 100644 index 000000000..5b07d7ad9 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessFiledRule.cs @@ -0,0 +1,19 @@ +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据访问控制规则:字段 +/// +public class DataAccessFiledRule +{ + /// + /// 字段名称 + /// + public virtual string Field { get; protected set; } + public DataAccessFiledRule() + { + } + + public DataAccessFiledRule(string field) + { + Field = field; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOperation.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOperation.cs new file mode 100644 index 000000000..b0b2cbec1 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOperation.cs @@ -0,0 +1,7 @@ +namespace LINGYUN.Abp.DataProtection; +public enum DataAccessOperation +{ + Read, + Write, + Delete +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOwner.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOwner.cs new file mode 100644 index 000000000..4daad0b06 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessOwner.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using Volo.Abp.Auditing; + +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据拥有者 +/// +public class DataAccessOwner : IMayHaveCreator +{ + public Guid? CreatorId { get; set; } + public string[] Roles { get; set; } + public string[] OrganizaztionUnits { get; set; } + protected DataAccessOwner() + { + } + + public DataAccessOwner(Guid? creatorId, string[] roles, string[] organizaztionUnits) + { + CreatorId = creatorId; + Roles = roles; + OrganizaztionUnits = organizaztionUnits; + } + + public bool IsInRole(string[] roles) + { + return Roles != null && Roles.Any(r => roles.Contains(r)); + } + + public bool IsInOrganizaztionUnit(string[] organizaztionUnits) + { + return OrganizaztionUnits != null && OrganizaztionUnits.Any(ou => organizaztionUnits.Contains(ou)); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRole.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRole.cs new file mode 100644 index 000000000..75dd30252 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRole.cs @@ -0,0 +1,23 @@ +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据访问角色 +/// +public enum DataAccessRole +{ + /// + /// 所有 + /// + All = 0, + /// + /// 用户 + /// + User = 1, + /// + /// 角色 + /// + Role = 2, + /// + /// 组织机构 + /// + OrganizationUnit = 3, +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRule.cs new file mode 100644 index 000000000..b8255ddd6 --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRule.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.DataProtection; +/// +/// 数据访问控制规则 +/// +public class DataAccessRule +{ + /// + /// 实体类型全名 + /// + public virtual string EntityTypeFullName { get; protected set; } + /// + /// 数据访问操作 + /// + public virtual DataAccessOperation Operation { get; protected set; } + /// + /// 数据访问角色 + /// + public virtual DataAccessRole Role { get; protected set; } + /// + /// 资源访问者 + /// + public virtual string Visitor { get; protected set; } + /// + /// 字段访问控制 + /// + public virtual List Fileds { get; protected set; } + /// + /// 自定义表达式 + /// + public virtual List Expressions { get; protected set; } + protected DataAccessRule() + { + Fileds = []; + Expressions = []; + } + + public DataAccessRule( + string entityTypeFullName, + DataAccessOperation operation = DataAccessOperation.Read, + DataAccessRole role = DataAccessRole.All, + string visitor = null, + List fileds = null, + List expressions = null) + { + EntityTypeFullName = entityTypeFullName; + Operation = operation; + Role = role; + Visitor = visitor; + Fileds = fileds ?? []; + Expressions = expressions ?? []; + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRuleInfo.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRuleInfo.cs new file mode 100644 index 000000000..b62f66d6a --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataAccessRuleInfo.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace LINGYUN.Abp.DataProtection; +public class DataAccessRuleInfo +{ + public List Rules { get; } + public DataAccessRuleInfo(List rules) + { + Rules = rules ?? new List(); + } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectionAsyncQueryableProvider.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectionAsyncQueryableProvider.cs deleted file mode 100644 index 31e7780dc..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/DataProtectionAsyncQueryableProvider.cs +++ /dev/null @@ -1,352 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using Volo.Abp.Linq; - -namespace LINGYUN.Abp.DataProtection -{ - public class DataProtectionAsyncQueryableProvider : IAsyncQueryableProvider - { - public Task AllAsync( - IQueryable queryable, - Expression> predicate, - CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AnyAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AnyAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task AverageAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public bool CanExecute(IQueryable queryable) - { - throw new NotImplementedException(); - } - - public Task ContainsAsync(IQueryable queryable, T item, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task CountAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task CountAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task FirstAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task FirstAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task FirstOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task FirstOrDefaultAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task LastAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task LastAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task LastOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task LastOrDefaultAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task LongCountAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task LongCountAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task MaxAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task MaxAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task MinAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task MinAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SingleAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SingleAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SingleOrDefaultAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SingleOrDefaultAsync(IQueryable queryable, Expression> predicate, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable source, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task SumAsync(IQueryable queryable, Expression> selector, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task ToArrayAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - - public Task> ToListAsync(IQueryable queryable, CancellationToken cancellationToken = default) - { - throw new NotImplementedException(); - } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ExpressionType.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ExpressionType.cs deleted file mode 100644 index e38ccea80..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ExpressionType.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace LINGYUN.Abp.DataProtection -{ - public enum ExpressionType - { - Contains, - Equal, - LessThan, - LessThanOrEqual, - GreaterThan, - GreaterThanOrEqual, - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessCache.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessCache.cs new file mode 100644 index 000000000..2244fcfda --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataAccessCache.cs @@ -0,0 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LINGYUN.Abp.DataProtection; +public interface IDataAccessCache +{ +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectdChecker.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectdChecker.cs deleted file mode 100644 index 6642d9c8c..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtectdChecker.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Threading.Tasks; - -namespace LINGYUN.Abp.DataProtection -{ - /// - /// 实现此接口 - /// 检查资源的访问权限 - /// - public interface IDataProtectdChecker - { - /// - /// 资源是否拥有某种行为的访问权限 - /// - /// 受保护的资源(实体) - /// 访问行为 - /// 不管是否拥有访问权限,请返回非空结果,由EF模块检查 - Task IsGrantedAsync(ProtectBehavior behavior = ProtectBehavior.All); - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtection.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtection.cs deleted file mode 100644 index 987b51a14..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IDataProtection.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace LINGYUN.Abp.DataProtection -{ - /// - /// 实现接口 - /// 数据访问保护 - /// - public interface IDataProtection - { - string Owner { get; } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IHasDataAccess.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IHasDataAccess.cs new file mode 100644 index 000000000..1bbd73f8f --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/IHasDataAccess.cs @@ -0,0 +1,5 @@ +namespace LINGYUN.Abp.DataProtection; +public interface IHasDataAccess +{ + public DataAccessOwner Owner { get; } +} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectBehavior.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectBehavior.cs deleted file mode 100644 index a261fbfa8..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectBehavior.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace LINGYUN.Abp.DataProtection -{ - /// - /// 保护行为 - /// - public enum ProtectBehavior - { - /// - /// 所有 - /// - All, - /// - /// 查询 - /// - Query, - /// - /// 新增 - /// - Insert, - /// - /// 修改 - /// - Update, - /// - /// 删除 - /// - Delete - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectedField.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectedField.cs deleted file mode 100644 index 53b416be5..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectedField.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace LINGYUN.Abp.DataProtection -{ - public class ProtectedField - { - /// - /// 资源 - /// - public string Resource { get; set; } - /// - /// 资源拥有者 - /// - public string Owner { get; set; } - /// - /// 资源访问者 - /// - public string Visitor { get; set; } - /// - /// 字段 - /// - public string Field { get; set; } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectedFieldRule.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectedFieldRule.cs deleted file mode 100644 index 911c0585a..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectedFieldRule.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; - -namespace LINGYUN.Abp.DataProtection -{ - public class ProtectedFieldRule - { - /// - /// 资源 - /// - public string Resource { get; set; } - /// - /// 资源拥有者 - /// - public string Owner { get; set; } - /// - /// 资源访问者 - /// - public string Visitor { get; set; } - /// - /// 字段 - /// - public string Field { get; set; } - /// - /// 值 - /// - public object Value { get; set; } - /// - /// 连接类型 - /// Or 或 - /// And 且 - /// - public PredicateOperator Logic { get; set; } - /// - /// 操作符 - /// - public ExpressionType Operator { get; set; } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectedResource.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectedResource.cs deleted file mode 100644 index c8924792a..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ProtectedResource.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace LINGYUN.Abp.DataProtection -{ - public class ProtectedResource - { - /// - /// 资源 - /// - public string Resource { get; set; } - /// - /// 资源拥有者 - /// - public string Owner { get; set; } - /// - /// 资源访问者 - /// - public string Visitor { get; set; } - /// - /// 优先级 - /// 值越大排名越靠前 - /// - public int Priority { get; set; } - /// - /// 行为 - /// - public ProtectBehavior Behavior { get; set; } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ResourceGrantedResult.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ResourceGrantedResult.cs deleted file mode 100644 index 99f4612ee..000000000 --- a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/LINGYUN/Abp/DataProtection/ResourceGrantedResult.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace LINGYUN.Abp.DataProtection -{ - public class ResourceGrantedResult - { - public bool Succeeded => Resource != null; - public ProtectedResource Resource { get; } - public ProtectedField[] Fields { get; } - public ProtectedFieldRule[] Rules { get; } - public ResourceGrantedResult( - ProtectedResource resource, - ProtectedField[] fields, - ProtectedFieldRule[] rules) - { - Resource = resource; - Fields = fields; - Rules = rules; - } - } -} diff --git a/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/Volo/Abp/Uow/IUnitOfWorkDataAccessExtensions.cs b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/Volo/Abp/Uow/IUnitOfWorkDataAccessExtensions.cs new file mode 100644 index 000000000..18a6afcba --- /dev/null +++ b/aspnet-core/framework/data-protection/LINGYUN.Abp.DataProtection/Volo/Abp/Uow/IUnitOfWorkDataAccessExtensions.cs @@ -0,0 +1,24 @@ +using LINGYUN.Abp.DataProtection; + +namespace Volo.Abp.Uow; +public static class IUnitOfWorkDataAccessExtensions +{ + private const string DataAccessRuleKey = "LINGYUN.Abp.DataProtection.DataAccess"; + + public static IUnitOfWork SetAccessRuleInfo( + this IUnitOfWork unitOfWork, + DataAccessRuleInfo dataAccessRuleInfo) + { + unitOfWork.RemoveItem(DataAccessRuleKey); + unitOfWork.AddItem(DataAccessRuleKey, dataAccessRuleInfo); + + return unitOfWork; + } + + public static DataAccessRuleInfo GetAccessRuleInfo( + this IUnitOfWork unitOfWork) + { + return unitOfWork.GetItemOrDefault(DataAccessRuleKey) + ?? new DataAccessRuleInfo(null); + } +} diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestModule.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestModule.cs index 6c503e4ca..ca8d99232 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestModule.cs +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/AbpDataProtectionTestModule.cs @@ -12,7 +12,7 @@ public class AbpDataProtectionTestModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { - context.Services.AddAbpDbContext(options => + context.Services.AddAbpDbContext(options => { options.AddRepository(); }); diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/EfCoreFakeProtectionObjectRepository.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/EfCoreFakeProtectionObjectRepository.cs index 3e071dfc0..4c7de7efc 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/EfCoreFakeProtectionObjectRepository.cs +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/EfCoreFakeProtectionObjectRepository.cs @@ -1,14 +1,15 @@ using LINGYUN.Abp.DataProtection.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; namespace LINGYUN.Abp.DataProtection { public class EfCoreFakeProtectionObjectRepository : - EfCoreDataProtectionRepositoryBase, + EfCoreRepository, IFakeProtectionObjectRepository { public EfCoreFakeProtectionObjectRepository( - IDbContextProvider dbContextProvider) + IDbContextProvider dbContextProvider) : base(dbContextProvider) { } diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeDataProtectdChecker.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeDataProtectdChecker.cs deleted file mode 100644 index 9d1d7b608..000000000 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeDataProtectdChecker.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Threading.Tasks; -using Volo.Abp.DependencyInjection; -using Volo.Abp.Uow; - -namespace LINGYUN.Abp.DataProtection -{ - public class FakeDataProtectdChecker : IDataProtectdChecker, ISingletonDependency - { - private readonly IUnitOfWorkManager _unitOfWorkManager; - - public FakeDataProtectdChecker(IUnitOfWorkManager unitOfWorkManager) - { - _unitOfWorkManager = unitOfWorkManager; - } - - public virtual Task IsGrantedAsync(ProtectBehavior behavior = ProtectBehavior.All) - { - var cacheItem = _unitOfWorkManager.Current.Items["ResourceGranted"]; - var result = cacheItem.As(); - - return Task.FromResult(result); - } - } -} diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeDataProtectedDbContext.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeDataProtectedDbContext.cs deleted file mode 100644 index d247afb82..000000000 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeDataProtectedDbContext.cs +++ /dev/null @@ -1,24 +0,0 @@ -using LINGYUN.Abp.DataProtection.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore; - -namespace LINGYUN.Abp.DataProtection -{ - public class FakeDataProtectedDbContext : AbpDataProtectionDbContext - { - public FakeDataProtectedDbContext( - DbContextOptions options) - : base(options) - { - } - - protected override void OnModelCreating(ModelBuilder modelBuilder) - { - base.OnModelCreating(modelBuilder); - - modelBuilder.Entity(b => - { - b.Property(p => p.Owner).HasColumnName(nameof(IDataProtection.Owner)).HasMaxLength(200); - }); - } - } -} diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeProtectionObject.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeProtectionObject.cs index 14c2ab767..7423bfb91 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeProtectionObject.cs +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/FakeProtectionObject.cs @@ -2,9 +2,8 @@ namespace LINGYUN.Abp.DataProtection { - public class FakeProtectionObject : Entity, IDataProtection + public class FakeProtectionObject : Entity, IHasDataAccess { - public virtual string Owner { get; set; } public virtual string Protect1 { get; set; } public virtual string Protect2 { get; set; } public virtual string Value1 { get; set; } @@ -12,5 +11,6 @@ public class FakeProtectionObject : Entity, IDataProtection public virtual int ProtectNum1 { get; set; } public virtual int ProtectNum2 { get; set; } public virtual int Num3 { get; set; } + public DataAccessOwner Owner { get; set; } } } diff --git a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/ProtectionFieldTests.cs b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/ProtectionFieldTests.cs index 7a3bcf8fd..e9a2449ca 100644 --- a/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/ProtectionFieldTests.cs +++ b/aspnet-core/tests/LINGYUN.Abp.DataProtection.Tests/LINGYUN/Abp/DataProtection/ProtectionFieldTests.cs @@ -1,12 +1,11 @@ -using System.Collections.Generic; -using System.Linq; +using Shouldly; +using System; +using System.Collections.Generic; +using System.Security.Claims; using System.Threading.Tasks; -using Xunit; using Volo.Abp.Security.Claims; -using System.Security.Claims; -using System; -using Shouldly; using Volo.Abp.Uow; +using Xunit; namespace LINGYUN.Abp.DataProtection { @@ -71,74 +70,62 @@ public async virtual Task FakeAsync() await WithUnitOfWorkAsync(async () => { - var resource = new ProtectedResource - { - Resource = typeof(FakeProtectionObject).FullName, - Behavior = ProtectBehavior.All, - Owner = "user1", - Priority = 10, - Visitor = "user1,role1" - }; - - var fields = new List() - { - new ProtectedField - { - Field = nameof(FakeProtectionObject.Num3), - Owner = "user1", - Resource = resource.Resource, - Visitor = "", - }, - new ProtectedField - { - Field = nameof(FakeProtectionObject.Value1), - Owner = "user2", - Resource = resource.Resource, - Visitor = "", - }, - new ProtectedField - { - Field = nameof(FakeProtectionObject.Value2), - Owner = "user1", - Resource = resource.Resource, - Visitor = "", - }, - new ProtectedField - { - Field = nameof(FakeProtectionObject.Protect1), - Owner = "role1", - Resource = resource.Resource, - Visitor = "", - }, - }; - - var rules = new List() - { - new ProtectedFieldRule - { - Field = nameof(FakeProtectionObject.Protect1), - Logic = PredicateOperator.And, - Operator = ExpressionType.Equal, - Resource = resource.Resource, - Value = "test" - }, - new ProtectedFieldRule - { - Field = nameof(FakeProtectionObject.Num3), - Logic = PredicateOperator.Or, - Operator = ExpressionType.LessThanOrEqual, - Resource = resource.Resource, - Value = 300 - }, - }; + var user1Rule = new DataAccessRule( + typeof(FakeProtectionObject).FullName, + DataAccessOperation.Write, + DataAccessRole.User, + "user1", + [ + new(nameof(FakeProtectionObject.Num3)), + new(nameof(FakeProtectionObject.Value2)), + ]); + var user2Rule = new DataAccessRule( + typeof(FakeProtectionObject).FullName, + DataAccessOperation.Write, + DataAccessRole.User, + "user2", + [ + new(nameof(FakeProtectionObject.Value1)), + ]); + var role1Rule = new DataAccessRule( + typeof(FakeProtectionObject).FullName, + DataAccessOperation.Write, + DataAccessRole.Role, + "role1", + [ + new(nameof(FakeProtectionObject.Protect1)), + ]); + + var dataAccessRule = new DataAccessRuleInfo( + [ + user1Rule, + user2Rule, + role1Rule, + ]); + + //var rules = new List() + //{ + // new ProtectedFieldRule + // { + // Field = nameof(FakeProtectionObject.Protect1), + // Logic = PredicateOperator.And, + // Operator = ExpressionType.Equal, + // Resource = resource.Resource, + // Value = "test" + // }, + // new ProtectedFieldRule + // { + // Field = nameof(FakeProtectionObject.Num3), + // Logic = PredicateOperator.Or, + // Operator = ExpressionType.LessThanOrEqual, + // Resource = resource.Resource, + // Value = 300 + // }, + //}; var unitOfWorkManager = GetRequiredService(); - unitOfWorkManager.Current.AddItem( - "ResourceGranted", - new ResourceGrantedResult( - resource, - fields.ToArray(), - rules.ToArray())); + + unitOfWorkManager.Current.SetAccessRuleInfo(dataAccessRule); var identity = new ClaimsIdentity(); identity.AddClaim(new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString())); @@ -153,74 +140,61 @@ await WithUnitOfWorkAsync(async () => await WithUnitOfWorkAsync(async () => { - var resource = new ProtectedResource - { - Resource = typeof(FakeProtectionObject).FullName, - Behavior = ProtectBehavior.All, - Owner = "user1", - Priority = 10, - Visitor = "user1,role1" - }; - - var fields = new List() - { - new ProtectedField - { - Field = nameof(FakeProtectionObject.Num3), - Owner = "user1", - Resource = resource.Resource, - Visitor = "", - }, - new ProtectedField - { - Field = nameof(FakeProtectionObject.Value1), - Owner = "user2", - Resource = resource.Resource, - Visitor = "", - }, - new ProtectedField - { - Field = nameof(FakeProtectionObject.Value2), - Owner = "user1", - Resource = resource.Resource, - Visitor = "", - }, - new ProtectedField - { - Field = nameof(FakeProtectionObject.Protect1), - Owner = "role1", - Resource = resource.Resource, - Visitor = "", - }, - }; - - var rules = new List() - { - new ProtectedFieldRule - { - Field = nameof(FakeProtectionObject.Protect1), - Logic = PredicateOperator.And, - Operator = ExpressionType.Equal, - Resource = resource.Resource, - Value = "test" - }, - new ProtectedFieldRule - { - Field = nameof(FakeProtectionObject.Num3), - Logic = PredicateOperator.Or, - Operator = ExpressionType.LessThanOrEqual, - Resource = resource.Resource, - Value = 300 - }, - }; + var user1Rule = new DataAccessRule( + typeof(FakeProtectionObject).FullName, + DataAccessOperation.Read, + DataAccessRole.User, + "user1", + [ + new(nameof(FakeProtectionObject.Num3)), + new(nameof(FakeProtectionObject.Value2)), + ]); + var user2Rule = new DataAccessRule( + typeof(FakeProtectionObject).FullName, + DataAccessOperation.Write, + DataAccessRole.User, + "user2", + [ + new(nameof(FakeProtectionObject.Value1)), + ]); + var role1Rule = new DataAccessRule( + typeof(FakeProtectionObject).FullName, + DataAccessOperation.Write, + DataAccessRole.Role, + "role1", + [ + new(nameof(FakeProtectionObject.Protect1)), + ]); + + var dataAccessRule = new DataAccessRuleInfo( + [ + user1Rule, + user2Rule, + role1Rule, + ]); + + //var rules = new List() + //{ + // new ProtectedFieldRule + // { + // Field = nameof(FakeProtectionObject.Protect1), + // Logic = PredicateOperator.And, + // Operator = ExpressionType.Equal, + // Resource = resource.Resource, + // Value = "test" + // }, + // new ProtectedFieldRule + // { + // Field = nameof(FakeProtectionObject.Num3), + // Logic = PredicateOperator.Or, + // Operator = ExpressionType.LessThanOrEqual, + // Resource = resource.Resource, + // Value = 300 + // }, + //}; var unitOfWorkManager = GetRequiredService(); - unitOfWorkManager.Current.AddItem( - "ResourceGranted", - new ResourceGrantedResult( - resource, - fields.ToArray(), - rules.ToArray())); + unitOfWorkManager.Current.SetAccessRuleInfo(dataAccessRule); var identity2 = new ClaimsIdentity(); identity2.AddClaim(new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString())); @@ -235,52 +209,23 @@ await WithUnitOfWorkAsync(async () => await WithUnitOfWorkAsync(async () => { - var resource = new ProtectedResource - { - Resource = typeof(FakeProtectionObject).FullName, - Behavior = ProtectBehavior.All, - Priority = 10, - Visitor = "user3" - }; - - var fields = new List() - { - new ProtectedField - { - Field = nameof(FakeProtectionObject.Num3), - Owner = "user1", - Resource = resource.Resource, - Visitor = "", - } - }; - - var rules = new List() - { - new ProtectedFieldRule - { - Field = nameof(FakeProtectionObject.Protect1), - Logic = PredicateOperator.And, - Operator = ExpressionType.Equal, - Resource = resource.Resource, - Value = "test" - }, - new ProtectedFieldRule - { - Field = nameof(FakeProtectionObject.Num3), - Logic = PredicateOperator.Or, - Operator = ExpressionType.LessThanOrEqual, - Resource = resource.Resource, - Value = 300 - }, - }; + var user1Rule = new DataAccessRule( + typeof(FakeProtectionObject).FullName, + DataAccessOperation.Read, + DataAccessRole.User, + "user3", + [ + new(nameof(FakeProtectionObject.Num3)), + new(nameof(FakeProtectionObject.Value2)), + ]); + + var dataAccessRule = new DataAccessRuleInfo( + [ + user1Rule, + ]); var unitOfWorkManager = GetRequiredService(); - unitOfWorkManager.Current.AddItem( - "ResourceGranted", - new ResourceGrantedResult( - resource, - fields.ToArray(), - rules.ToArray())); + unitOfWorkManager.Current.SetAccessRuleInfo(dataAccessRule); var identity3 = new ClaimsIdentity(); identity3.AddClaim(new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString()));