committed by
GitHub
34 changed files with 585 additions and 1099 deletions
@ -1,14 +1,145 @@ |
|||||
using Microsoft.EntityFrameworkCore; |
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.EntityFrameworkCore; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using Volo.Abp.Uow; |
||||
|
using Volo.Abp.Users; |
||||
|
|
||||
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore |
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore |
||||
{ |
{ |
||||
public class AbpDataProtectionDbContext<TDbContext> : AbpDbContext<TDbContext> |
public class AbpDataProtectionDbContext : AbpDbContext<AbpDataProtectionDbContext> |
||||
where TDbContext : DbContext |
|
||||
{ |
{ |
||||
|
protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetService<ICurrentUser>(); |
||||
|
|
||||
|
protected virtual bool IsDataAccessFilterEnabled => DataFilter?.IsEnabled<IHasDataAccess>() ?? false; |
||||
|
|
||||
public AbpDataProtectionDbContext( |
public AbpDataProtectionDbContext( |
||||
DbContextOptions<TDbContext> options) : base(options) |
DbContextOptions<AbpDataProtectionDbContext> 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<Func<TEntity, bool>> CreateFilterExpression<TEntity>() |
||||
|
{ |
||||
|
var expression = base.CreateFilterExpression<TEntity>(); |
||||
|
|
||||
|
if (typeof(IHasDataAccess).IsAssignableFrom(typeof(TEntity))) |
||||
|
{ |
||||
|
Expression<Func<TEntity, bool>> expression2 = (TEntity e) => !IsDataAccessFilterEnabled || CreateFilterExpression(e, AccessRuleInfo); |
||||
|
expression = (Expression<Func<TEntity, bool>>)((expression == null) ? ((LambdaExpression)expression2) : ((LambdaExpression)QueryFilterExpressionHelper.CombineExpressions(expression, expression2))); |
||||
|
} |
||||
|
|
||||
|
return expression; |
||||
|
} |
||||
|
|
||||
|
protected static bool CreateFilterExpression<TEntity>(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; |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -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 |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 受保护的资源仓储接口需要继承此接口,否则需要自行实现过滤器
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TDbContext"></typeparam>
|
|
||||
/// <typeparam name="TEntity"></typeparam>
|
|
||||
/// <typeparam name="TKey"></typeparam>
|
|
||||
public abstract class EfCoreDataProtectionRepositoryBase<TDbContext, TEntity, TKey> : EfCoreRepository<TDbContext, TEntity, TKey> |
|
||||
where TEntity : class, IEntity<TKey>, IDataProtection |
|
||||
where TDbContext: IEfCoreDbContext |
|
||||
{ |
|
||||
protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetService<ICurrentUser>(); |
|
||||
protected IDataProtectdChecker DataProtectdChecker => LazyServiceProvider.LazyGetService<IDataProtectdChecker>(); |
|
||||
protected EfCoreDataProtectionRepositoryBase( |
|
||||
IDbContextProvider<TDbContext> dbContextProvider) |
|
||||
: base(dbContextProvider) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
public override async Task<TEntity> 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<TEntity> 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<List<TEntity>> 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<TEntity> 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<List<TEntity>> GetListAsync( |
|
||||
Expression<Func<TEntity, bool>> 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<TKey> 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<Func<TEntity, bool>> 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<IQueryable<TEntity>> WithDetailsAsync(ProtectBehavior behavior = ProtectBehavior.All) |
|
||||
{ |
|
||||
if (typeof(IDataProtection).IsAssignableFrom(typeof(TEntity))) |
|
||||
{ |
|
||||
var result = await DataProtectdChecker.IsGrantedAsync<TEntity>(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<IQueryable<TEntity>> WithDetailsAsync(ResourceGrantedResult resourceGranted) |
|
||||
{ |
|
||||
if (AbpEntityOptions.DefaultWithDetailsFunc == null) |
|
||||
{ |
|
||||
return await GetQueryableAsync(resourceGranted); |
|
||||
} |
|
||||
|
|
||||
return AbpEntityOptions.DefaultWithDetailsFunc(await GetQueryableAsync(resourceGranted)); |
|
||||
} |
|
||||
protected async virtual Task<IQueryable<TEntity>> GetQueryableAsync(ProtectBehavior behavior = ProtectBehavior.All) |
|
||||
{ |
|
||||
if (typeof(IDataProtection).IsAssignableFrom(typeof(TEntity))) |
|
||||
{ |
|
||||
var result = await DataProtectdChecker.IsGrantedAsync<TEntity>(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<IQueryable<TEntity>> 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<T> FilterResource<T>(IQueryable<T> 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<Func<T, bool>>(visitorExpr, pe)); |
|
||||
} |
|
||||
|
|
||||
return queryable; |
|
||||
} |
|
||||
|
|
||||
protected virtual IQueryable<T> FilterFieldRule<T>(IQueryable<T> queryable, IEnumerable<ProtectedFieldRule> rules) |
|
||||
where T : IDataProtection |
|
||||
{ |
|
||||
ParameterExpression pe = Expression.Parameter(typeof(T)); |
|
||||
|
|
||||
// 默认未指定访问规则
|
|
||||
// 则可访问所有允许的资源
|
|
||||
if (rules.Any()) |
|
||||
{ |
|
||||
Expression<Func<T, bool>> where = PredicateBuilder.New<T>((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<Func<T, bool>>(memberCondition, pe)); |
|
||||
break; |
|
||||
case PredicateOperator.Or: |
|
||||
where = where.Or(Expression.Lambda<Func<T, bool>>(memberCondition, pe)); |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
queryable = queryable.Where(where); |
|
||||
} |
|
||||
|
|
||||
return queryable; |
|
||||
} |
|
||||
|
|
||||
protected virtual IQueryable<T> FilterFieldReturn<T>(IQueryable<T> queryable, IEnumerable<ProtectedField> fields) |
|
||||
{ |
|
||||
// 默认未指定可访问字段则返回所有字段
|
|
||||
if (fields.Any()) |
|
||||
{ |
|
||||
ParameterExpression pe = Expression.Parameter(typeof(T)); |
|
||||
Type queryableResultType = typeof(T); |
|
||||
NewExpression ne = Expression.New(queryableResultType); |
|
||||
List<MemberAssignment> members = new List<MemberAssignment>(); |
|
||||
|
|
||||
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<Func<T, T>> personSelectExpression = Expression.Lambda<Func<T, T>>(mie, pe); |
|
||||
|
|
||||
queryable = queryable.Select(personSelectExpression); |
|
||||
} |
|
||||
|
|
||||
return queryable; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,11 +1,10 @@ |
|||||
using Volo.Abp.Modularity; |
using Volo.Abp.Domain; |
||||
using Volo.Abp.Threading; |
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 |
|
||||
{ |
|
||||
} |
|
||||
} |
} |
||||
|
|||||
@ -0,0 +1,30 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
public class DataAccessCacheItem |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 实体类型全名
|
||||
|
/// </summary>
|
||||
|
public string EntityTypeFullName { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 数据访问操作
|
||||
|
/// </summary>
|
||||
|
public DataAccessOperation Operation { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 数据访问角色
|
||||
|
/// </summary>
|
||||
|
public DataAccessRole Role { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 资源访问者
|
||||
|
/// </summary>
|
||||
|
public string Visitor { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 字段访问控制
|
||||
|
/// </summary>
|
||||
|
public List<DataAccessFiledRule> Fileds { get; set; } |
||||
|
/// <summary>
|
||||
|
/// 自定义表达式
|
||||
|
/// </summary>
|
||||
|
public List<DataAccessExpressionRule> Expressions { get; set; } |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
/// <summary>
|
||||
|
/// 数据访问实体控制
|
||||
|
/// </summary>
|
||||
|
public class DataAccessEntityRule |
||||
|
{ |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
/// <summary>
|
||||
|
/// 数据访问控制规则:自定义表达式
|
||||
|
/// </summary>
|
||||
|
public class DataAccessExpressionRule |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 表达式
|
||||
|
/// </summary>
|
||||
|
public virtual string Expression { get; protected set; } |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
/// <summary>
|
||||
|
/// 数据访问控制规则:字段
|
||||
|
/// </summary>
|
||||
|
public class DataAccessFiledRule |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 字段名称
|
||||
|
/// </summary>
|
||||
|
public virtual string Field { get; protected set; } |
||||
|
public DataAccessFiledRule() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public DataAccessFiledRule(string field) |
||||
|
{ |
||||
|
Field = field; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
public enum DataAccessOperation |
||||
|
{ |
||||
|
Read, |
||||
|
Write, |
||||
|
Delete |
||||
|
} |
||||
@ -0,0 +1,34 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using Volo.Abp.Auditing; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
/// <summary>
|
||||
|
/// 数据拥有者
|
||||
|
/// </summary>
|
||||
|
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)); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
/// <summary>
|
||||
|
/// 数据访问角色
|
||||
|
/// </summary>
|
||||
|
public enum DataAccessRole |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 所有
|
||||
|
/// </summary>
|
||||
|
All = 0, |
||||
|
/// <summary>
|
||||
|
/// 用户
|
||||
|
/// </summary>
|
||||
|
User = 1, |
||||
|
/// <summary>
|
||||
|
/// 角色
|
||||
|
/// </summary>
|
||||
|
Role = 2, |
||||
|
/// <summary>
|
||||
|
/// 组织机构
|
||||
|
/// </summary>
|
||||
|
OrganizationUnit = 3, |
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
/// <summary>
|
||||
|
/// 数据访问控制规则
|
||||
|
/// </summary>
|
||||
|
public class DataAccessRule |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 实体类型全名
|
||||
|
/// </summary>
|
||||
|
public virtual string EntityTypeFullName { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 数据访问操作
|
||||
|
/// </summary>
|
||||
|
public virtual DataAccessOperation Operation { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 数据访问角色
|
||||
|
/// </summary>
|
||||
|
public virtual DataAccessRole Role { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 资源访问者
|
||||
|
/// </summary>
|
||||
|
public virtual string Visitor { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 字段访问控制
|
||||
|
/// </summary>
|
||||
|
public virtual List<DataAccessFiledRule> Fileds { get; protected set; } |
||||
|
/// <summary>
|
||||
|
/// 自定义表达式
|
||||
|
/// </summary>
|
||||
|
public virtual List<DataAccessExpressionRule> Expressions { get; protected set; } |
||||
|
protected DataAccessRule() |
||||
|
{ |
||||
|
Fileds = []; |
||||
|
Expressions = []; |
||||
|
} |
||||
|
|
||||
|
public DataAccessRule( |
||||
|
string entityTypeFullName, |
||||
|
DataAccessOperation operation = DataAccessOperation.Read, |
||||
|
DataAccessRole role = DataAccessRole.All, |
||||
|
string visitor = null, |
||||
|
List<DataAccessFiledRule> fileds = null, |
||||
|
List<DataAccessExpressionRule> expressions = null) |
||||
|
{ |
||||
|
EntityTypeFullName = entityTypeFullName; |
||||
|
Operation = operation; |
||||
|
Role = role; |
||||
|
Visitor = visitor; |
||||
|
Fileds = fileds ?? []; |
||||
|
Expressions = expressions ?? []; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
public class DataAccessRuleInfo |
||||
|
{ |
||||
|
public List<DataAccessRule> Rules { get; } |
||||
|
public DataAccessRuleInfo(List<DataAccessRule> rules) |
||||
|
{ |
||||
|
Rules = rules ?? new List<DataAccessRule>(); |
||||
|
} |
||||
|
} |
||||
@ -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<bool> AllAsync<T>( |
|
||||
IQueryable<T> queryable, |
|
||||
Expression<Func<T, bool>> predicate, |
|
||||
CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<decimal> AverageAsync(IQueryable<decimal> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<decimal?> AverageAsync(IQueryable<decimal?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<decimal> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<decimal?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double> AverageAsync(IQueryable<int> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double?> AverageAsync(IQueryable<int?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double> AverageAsync(IQueryable<long> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double?> AverageAsync(IQueryable<long?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double> AverageAsync(IQueryable<double> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double?> AverageAsync(IQueryable<double?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<float> AverageAsync(IQueryable<float> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<float?> AverageAsync(IQueryable<float?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<float> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<float?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public bool CanExecute<T>(IQueryable<T> queryable) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<bool> ContainsAsync<T>(IQueryable<T> queryable, T item, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<int> CountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> FirstAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> FirstAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> LastAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> LastAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> MaxAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<TResult> MaxAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> MinAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<TResult> MinAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> SingleAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> SingleAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<decimal> SumAsync(IQueryable<decimal> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<decimal?> SumAsync(IQueryable<decimal?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<decimal> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<decimal?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<int> SumAsync(IQueryable<int> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<int?> SumAsync(IQueryable<int?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<int> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<int?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<long> SumAsync(IQueryable<long> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<long?> SumAsync(IQueryable<long?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<long> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<long?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double> SumAsync(IQueryable<double> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double?> SumAsync(IQueryable<double?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<double?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<float> SumAsync(IQueryable<float> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<float?> SumAsync(IQueryable<float?> source, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<float> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<float?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<T[]> ToArrayAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
|
||||
{ |
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,12 +0,0 @@ |
|||||
namespace LINGYUN.Abp.DataProtection |
|
||||
{ |
|
||||
public enum ExpressionType |
|
||||
{ |
|
||||
Contains, |
|
||||
Equal, |
|
||||
LessThan, |
|
||||
LessThanOrEqual, |
|
||||
GreaterThan, |
|
||||
GreaterThanOrEqual, |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,8 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Text; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
public interface IDataAccessCache |
||||
|
{ |
||||
|
} |
||||
@ -1,19 +0,0 @@ |
|||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace LINGYUN.Abp.DataProtection |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 实现此接口
|
|
||||
/// 检查资源的访问权限
|
|
||||
/// </summary>
|
|
||||
public interface IDataProtectdChecker |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 资源是否拥有某种行为的访问权限
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="T">受保护的资源(实体)</typeparam>
|
|
||||
/// <param name="behavior">访问行为</param>
|
|
||||
/// <returns>不管是否拥有访问权限,请返回非空结果,由EF模块检查</returns>
|
|
||||
Task<ResourceGrantedResult> IsGrantedAsync<T>(ProtectBehavior behavior = ProtectBehavior.All); |
|
||||
} |
|
||||
} |
|
||||
@ -1,11 +0,0 @@ |
|||||
namespace LINGYUN.Abp.DataProtection |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 实现接口
|
|
||||
/// 数据访问保护
|
|
||||
/// </summary>
|
|
||||
public interface IDataProtection |
|
||||
{ |
|
||||
string Owner { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,5 @@ |
|||||
|
namespace LINGYUN.Abp.DataProtection; |
||||
|
public interface IHasDataAccess |
||||
|
{ |
||||
|
public DataAccessOwner Owner { get; } |
||||
|
} |
||||
@ -1,29 +0,0 @@ |
|||||
namespace LINGYUN.Abp.DataProtection |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 保护行为
|
|
||||
/// </summary>
|
|
||||
public enum ProtectBehavior |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 所有
|
|
||||
/// </summary>
|
|
||||
All, |
|
||||
/// <summary>
|
|
||||
/// 查询
|
|
||||
/// </summary>
|
|
||||
Query, |
|
||||
/// <summary>
|
|
||||
/// 新增
|
|
||||
/// </summary>
|
|
||||
Insert, |
|
||||
/// <summary>
|
|
||||
/// 修改
|
|
||||
/// </summary>
|
|
||||
Update, |
|
||||
/// <summary>
|
|
||||
/// 删除
|
|
||||
/// </summary>
|
|
||||
Delete |
|
||||
} |
|
||||
} |
|
||||
@ -1,22 +0,0 @@ |
|||||
namespace LINGYUN.Abp.DataProtection |
|
||||
{ |
|
||||
public class ProtectedField |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 资源
|
|
||||
/// </summary>
|
|
||||
public string Resource { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 资源拥有者
|
|
||||
/// </summary>
|
|
||||
public string Owner { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 资源访问者
|
|
||||
/// </summary>
|
|
||||
public string Visitor { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 字段
|
|
||||
/// </summary>
|
|
||||
public string Field { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,40 +0,0 @@ |
|||||
using System; |
|
||||
using System.Linq; |
|
||||
using System.Linq.Expressions; |
|
||||
|
|
||||
namespace LINGYUN.Abp.DataProtection |
|
||||
{ |
|
||||
public class ProtectedFieldRule |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 资源
|
|
||||
/// </summary>
|
|
||||
public string Resource { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 资源拥有者
|
|
||||
/// </summary>
|
|
||||
public string Owner { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 资源访问者
|
|
||||
/// </summary>
|
|
||||
public string Visitor { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 字段
|
|
||||
/// </summary>
|
|
||||
public string Field { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 值
|
|
||||
/// </summary>
|
|
||||
public object Value { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 连接类型
|
|
||||
/// Or 或
|
|
||||
/// And 且
|
|
||||
/// </summary>
|
|
||||
public PredicateOperator Logic { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 操作符
|
|
||||
/// </summary>
|
|
||||
public ExpressionType Operator { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -1,27 +0,0 @@ |
|||||
namespace LINGYUN.Abp.DataProtection |
|
||||
{ |
|
||||
public class ProtectedResource |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// 资源
|
|
||||
/// </summary>
|
|
||||
public string Resource { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 资源拥有者
|
|
||||
/// </summary>
|
|
||||
public string Owner { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 资源访问者
|
|
||||
/// </summary>
|
|
||||
public string Visitor { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 优先级
|
|
||||
/// 值越大排名越靠前
|
|
||||
/// </summary>
|
|
||||
public int Priority { get; set; } |
|
||||
/// <summary>
|
|
||||
/// 行为
|
|
||||
/// </summary>
|
|
||||
public ProtectBehavior Behavior { get; set; } |
|
||||
} |
|
||||
} |
|
||||
@ -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; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -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<DataAccessRuleInfo>(DataAccessRuleKey) |
||||
|
?? new DataAccessRuleInfo(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<ResourceGrantedResult> IsGrantedAsync<T>(ProtectBehavior behavior = ProtectBehavior.All) |
|
||||
{ |
|
||||
var cacheItem = _unitOfWorkManager.Current.Items["ResourceGranted"]; |
|
||||
var result = cacheItem.As<ResourceGrantedResult>(); |
|
||||
|
|
||||
return Task.FromResult(result); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,24 +0,0 @@ |
|||||
using LINGYUN.Abp.DataProtection.EntityFrameworkCore; |
|
||||
using Microsoft.EntityFrameworkCore; |
|
||||
|
|
||||
namespace LINGYUN.Abp.DataProtection |
|
||||
{ |
|
||||
public class FakeDataProtectedDbContext : AbpDataProtectionDbContext<FakeDataProtectedDbContext> |
|
||||
{ |
|
||||
public FakeDataProtectedDbContext( |
|
||||
DbContextOptions<FakeDataProtectedDbContext> options) |
|
||||
: base(options) |
|
||||
{ |
|
||||
} |
|
||||
|
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder) |
|
||||
{ |
|
||||
base.OnModelCreating(modelBuilder); |
|
||||
|
|
||||
modelBuilder.Entity<FakeProtectionObject>(b => |
|
||||
{ |
|
||||
b.Property(p => p.Owner).HasColumnName(nameof(IDataProtection.Owner)).HasMaxLength(200); |
|
||||
}); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue