34 changed files with 585 additions and 1099 deletions
@ -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<TDbContext> : AbpDbContext<TDbContext> |
|||
where TDbContext : DbContext |
|||
public class AbpDataProtectionDbContext : AbpDbContext<AbpDataProtectionDbContext> |
|||
{ |
|||
protected ICurrentUser CurrentUser => LazyServiceProvider.LazyGetService<ICurrentUser>(); |
|||
|
|||
protected virtual bool IsDataAccessFilterEnabled => DataFilter?.IsEnabled<IHasDataAccess>() ?? false; |
|||
|
|||
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.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 |
|||
{ |
|||
} |
|||
} |
|||
|
|||
@ -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