committed by
GitHub
28 changed files with 1807 additions and 59 deletions
@ -0,0 +1,17 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.1</TargetFramework> |
||||
|
<LangVersion>9.0</LangVersion> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.EntityFrameworkCore" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.DataProtection\LINGYUN.Abp.DataProtection.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,14 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore |
||||
|
{ |
||||
|
public class AbpDataProtectionDbContext<TDbContext> : AbpDbContext<TDbContext> |
||||
|
where TDbContext : DbContext |
||||
|
{ |
||||
|
public AbpDataProtectionDbContext( |
||||
|
DbContextOptions<TDbContext> options) : base(options) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpDataProtectionModule), |
||||
|
typeof(AbpEntityFrameworkCoreModule))] |
||||
|
public class AbpDataProtectionEntityFrameworkCoreModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,358 @@ |
|||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.EntityFrameworkCore.Query.Internal; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Linq.Expressions; |
||||
|
using System.Threading; |
||||
|
using System.Threading.Tasks; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Linq; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// TODO: 需要实现动态数据权限规则
|
||||
|
/// </summary>
|
||||
|
[Dependency(ReplaceServices = true)] |
||||
|
public class DataProtectionAsyncQueryableProvider : IAsyncQueryableProvider, ISingletonDependency |
||||
|
{ |
||||
|
public bool CanExecute<T>(IQueryable<T> queryable) |
||||
|
{ |
||||
|
return queryable.Provider is EntityQueryProvider; |
||||
|
} |
||||
|
|
||||
|
public Task<bool> ContainsAsync<T>(IQueryable<T> queryable, T item, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.ContainsAsync(item, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AnyAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<bool> AnyAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AnyAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<bool> AllAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AllAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<int> CountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.CountAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<int> CountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.CountAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.LongCountAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<long> LongCountAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.LongCountAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> FirstAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.FirstAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> FirstAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.FirstAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.FirstOrDefaultAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> FirstOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.FirstOrDefaultAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> LastAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.LastAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> LastAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.LastAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.LastOrDefaultAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> LastOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.LastOrDefaultAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> SingleAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SingleAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> SingleAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SingleAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SingleOrDefaultAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> SingleOrDefaultAsync<T>(IQueryable<T> queryable, Expression<Func<T, bool>> predicate, |
||||
|
CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SingleOrDefaultAsync(predicate, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> MinAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.MinAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<TResult> MinAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.MinAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T> MaxAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.MaxAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<TResult> MaxAsync<T, TResult>(IQueryable<T> queryable, Expression<Func<T, TResult>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.MaxAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<decimal> SumAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<decimal?> SumAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<decimal> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<decimal?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<int> SumAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<int?> SumAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<int> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<int?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<long> SumAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<long?> SumAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<long> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<long?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double> SumAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double?> SumAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<float> SumAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<float?> SumAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<float> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<float?> SumAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.SumAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<decimal> AverageAsync(IQueryable<decimal> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<decimal?> AverageAsync(IQueryable<decimal?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<decimal> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<decimal?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, decimal?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double> AverageAsync(IQueryable<int> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double?> AverageAsync(IQueryable<int?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, int?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double> AverageAsync(IQueryable<long> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double?> AverageAsync(IQueryable<long?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, long?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double> AverageAsync(IQueryable<double> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double?> AverageAsync(IQueryable<double?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<double?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, double?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<float> AverageAsync(IQueryable<float> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<float?> AverageAsync(IQueryable<float?> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<float> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<float?> AverageAsync<T>(IQueryable<T> queryable, Expression<Func<T, float?>> selector, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.AverageAsync(selector, cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<List<T>> ToListAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.ToListAsync(cancellationToken); |
||||
|
} |
||||
|
|
||||
|
public Task<T[]> ToArrayAsync<T>(IQueryable<T> queryable, CancellationToken cancellationToken = default) |
||||
|
{ |
||||
|
return queryable.ToArrayAsync(cancellationToken); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,297 @@ |
|||||
|
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 virtual async 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 virtual async Task<IQueryable<TEntity>> WithDetailsAsync(ResourceGrantedResult resourceGranted) |
||||
|
{ |
||||
|
if (AbpEntityOptions.DefaultWithDetailsFunc == null) |
||||
|
{ |
||||
|
return await GetQueryableAsync(resourceGranted); |
||||
|
} |
||||
|
|
||||
|
return AbpEntityOptions.DefaultWithDetailsFunc(await GetQueryableAsync(resourceGranted)); |
||||
|
} |
||||
|
protected virtual async 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 virtual async 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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System; |
||||
|
using Volo.Abp; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection.EntityFrameworkCore |
||||
|
{ |
||||
|
public static class ProtectedEntityHelper |
||||
|
{ |
||||
|
public static void TrySetOwner( |
||||
|
IDataProtection protectedEntity, |
||||
|
Func<string> ownerFactory) |
||||
|
{ |
||||
|
ObjectHelper.TrySetProperty( |
||||
|
protectedEntity, |
||||
|
x => x.Owner, |
||||
|
ownerFactory, |
||||
|
new Type[] { }); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Threading" Version="4.4.0" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Threading; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpThreadingModule))] |
||||
|
public class AbpDataProtectionModule : AbpModule |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,352 @@ |
|||||
|
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(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
public enum ExpressionType |
||||
|
{ |
||||
|
Contains, |
||||
|
Equal, |
||||
|
LessThan, |
||||
|
LessThanOrEqual, |
||||
|
GreaterThan, |
||||
|
GreaterThanOrEqual, |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
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); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,11 @@ |
|||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 实现接口
|
||||
|
/// 数据访问保护
|
||||
|
/// </summary>
|
||||
|
public interface IDataProtection |
||||
|
{ |
||||
|
string Owner { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 保护行为
|
||||
|
/// </summary>
|
||||
|
public enum ProtectBehavior |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 所有
|
||||
|
/// </summary>
|
||||
|
All, |
||||
|
/// <summary>
|
||||
|
/// 查询
|
||||
|
/// </summary>
|
||||
|
Query, |
||||
|
/// <summary>
|
||||
|
/// 新增
|
||||
|
/// </summary>
|
||||
|
Insert, |
||||
|
/// <summary>
|
||||
|
/// 修改
|
||||
|
/// </summary>
|
||||
|
Update, |
||||
|
/// <summary>
|
||||
|
/// 删除
|
||||
|
/// </summary>
|
||||
|
Delete |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
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; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
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; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
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; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
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,28 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace /> |
||||
|
<IsPackable>false</IsPackable> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> |
||||
|
<PackageReference Include="xunit" Version="2.4.1" /> |
||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3"> |
||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
||||
|
<PrivateAssets>all</PrivateAssets> |
||||
|
</PackageReference> |
||||
|
<PackageReference Include="coverlet.collector" Version="1.3.0"> |
||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> |
||||
|
<PrivateAssets>all</PrivateAssets> |
||||
|
</PackageReference> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\modules\data-protection\LINGYUN.Abp.DataProtection.EntityFrameworkCore\LINGYUN.Abp.DataProtection.EntityFrameworkCore.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.EntityFrameworkCore.Tests\LINGYUN.Abp.EntityFrameworkCore.Tests.csproj" /> |
||||
|
<ProjectReference Include="..\LINGYUN.Abp.TestBase\LINGYUN.Abp.TestsBase.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,9 @@ |
|||||
|
using LINGYUN.Abp.Tests; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
public abstract class AbpDataProtectionTestBase : AbpTestsBase<AbpDataProtectionTestModule> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
using LINGYUN.Abp.DataProtection.EntityFrameworkCore; |
||||
|
using LINGYUN.Abp.EntityFrameworkCore.Tests; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.Modularity; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpDataProtectionEntityFrameworkCoreModule), |
||||
|
typeof(AbpEntityFrameworkCoreTestModule))] |
||||
|
public class AbpDataProtectionTestModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddAbpDbContext<FakeDataProtectedDbContext>(options => |
||||
|
{ |
||||
|
options.AddRepository<FakeProtectionObject, EfCoreFakeProtectionObjectRepository>(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using LINGYUN.Abp.DataProtection.EntityFrameworkCore; |
||||
|
using Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
public class EfCoreFakeProtectionObjectRepository : |
||||
|
EfCoreDataProtectionRepositoryBase<FakeDataProtectedDbContext, FakeProtectionObject, int>, |
||||
|
IFakeProtectionObjectRepository |
||||
|
{ |
||||
|
public EfCoreFakeProtectionObjectRepository( |
||||
|
IDbContextProvider<FakeDataProtectedDbContext> dbContextProvider) |
||||
|
: base(dbContextProvider) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
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); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
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); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
using Volo.Abp.Domain.Entities; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
public class FakeProtectionObject : Entity<int>, IDataProtection |
||||
|
{ |
||||
|
public virtual string Owner { get; set; } |
||||
|
public virtual string Protect1 { get; set; } |
||||
|
public virtual string Protect2 { get; set; } |
||||
|
public virtual string Value1 { get; set; } |
||||
|
public virtual string Value2 { get; set; } |
||||
|
public virtual int ProtectNum1 { get; set; } |
||||
|
public virtual int ProtectNum2 { get; set; } |
||||
|
public virtual int Num3 { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
public interface IFakeProtectionObjectRepository : IBasicRepository<FakeProtectionObject, int> |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,297 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Xunit; |
||||
|
using Volo.Abp.Security.Claims; |
||||
|
using System.Security.Claims; |
||||
|
using System; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Uow; |
||||
|
|
||||
|
namespace LINGYUN.Abp.DataProtection |
||||
|
{ |
||||
|
public class ProtectionFieldTests : AbpDataProtectionTestBase |
||||
|
{ |
||||
|
private readonly IFakeProtectionObjectRepository _repository; |
||||
|
private readonly ICurrentPrincipalAccessor _accessor; |
||||
|
|
||||
|
public ProtectionFieldTests() |
||||
|
{ |
||||
|
_repository = GetRequiredService<IFakeProtectionObjectRepository>(); |
||||
|
_accessor = GetRequiredService<ICurrentPrincipalAccessor>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public virtual async Task FakeAsync() |
||||
|
{ |
||||
|
|
||||
|
var values = new List<FakeProtectionObject>() |
||||
|
{ |
||||
|
new FakeProtectionObject |
||||
|
{ |
||||
|
Protect1 = "Protect1", |
||||
|
Protect2 = "Protect1", |
||||
|
Value1 = "Value1", |
||||
|
Value2 = "Value1", |
||||
|
ProtectNum1 = 100, |
||||
|
ProtectNum2 = 200, |
||||
|
Num3 = 400 |
||||
|
}, |
||||
|
new FakeProtectionObject |
||||
|
{ |
||||
|
Protect1 = "test", |
||||
|
Protect2 = "Protect2", |
||||
|
Value1 = "Value2", |
||||
|
Value2 = "Value2", |
||||
|
ProtectNum1 = 1000, |
||||
|
ProtectNum2 = 2000, |
||||
|
Num3 = 3000 |
||||
|
}, |
||||
|
new FakeProtectionObject |
||||
|
{ |
||||
|
Protect1 = "test1", |
||||
|
Protect2 = "Protect3", |
||||
|
Value1 = "Value3", |
||||
|
Value2 = "Value3", |
||||
|
ProtectNum1 = 10000, |
||||
|
ProtectNum2 = 20000, |
||||
|
Num3 = 300 |
||||
|
}, |
||||
|
new FakeProtectionObject |
||||
|
{ |
||||
|
Protect1 = "test3", |
||||
|
Protect2 = "Protect4", |
||||
|
Value1 = "Value4", |
||||
|
Value2 = "Value4", |
||||
|
ProtectNum1 = 10000, |
||||
|
ProtectNum2 = 20000, |
||||
|
Num3 = 300 |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
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<ProtectedField>() |
||||
|
{ |
||||
|
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<ProtectedFieldRule>() |
||||
|
{ |
||||
|
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<IUnitOfWorkManager>(); |
||||
|
unitOfWorkManager.Current.AddItem<ResourceGrantedResult>( |
||||
|
"ResourceGranted", |
||||
|
new ResourceGrantedResult( |
||||
|
resource, |
||||
|
fields.ToArray(), |
||||
|
rules.ToArray())); |
||||
|
|
||||
|
var identity = new ClaimsIdentity(); |
||||
|
identity.AddClaim(new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString())); |
||||
|
identity.AddClaim(new Claim(AbpClaimTypes.UserName, "user1")); |
||||
|
identity.AddClaim(new Claim(AbpClaimTypes.Role, "role1")); |
||||
|
identity.AddClaim(new Claim(AbpClaimTypes.Role, "role2")); |
||||
|
using (_accessor.Change(new ClaimsPrincipal(identity))) |
||||
|
{ |
||||
|
await _repository.InsertManyAsync(values, true); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
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<ProtectedField>() |
||||
|
{ |
||||
|
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<ProtectedFieldRule>() |
||||
|
{ |
||||
|
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<IUnitOfWorkManager>(); |
||||
|
unitOfWorkManager.Current.AddItem<ResourceGrantedResult>( |
||||
|
"ResourceGranted", |
||||
|
new ResourceGrantedResult( |
||||
|
resource, |
||||
|
fields.ToArray(), |
||||
|
rules.ToArray())); |
||||
|
|
||||
|
var identity2 = new ClaimsIdentity(); |
||||
|
identity2.AddClaim(new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString())); |
||||
|
identity2.AddClaim(new Claim(AbpClaimTypes.UserName, "user2")); |
||||
|
identity2.AddClaim(new Claim(AbpClaimTypes.Role, "role2")); |
||||
|
using (_accessor.Change(identity2)) |
||||
|
{ |
||||
|
var result = await _repository.GetListAsync(); |
||||
|
result.Count.ShouldBe(3); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
await WithUnitOfWorkAsync(async () => |
||||
|
{ |
||||
|
var resource = new ProtectedResource |
||||
|
{ |
||||
|
Resource = typeof(FakeProtectionObject).FullName, |
||||
|
Behavior = ProtectBehavior.All, |
||||
|
Priority = 10, |
||||
|
Visitor = "user3" |
||||
|
}; |
||||
|
|
||||
|
var fields = new List<ProtectedField>() |
||||
|
{ |
||||
|
new ProtectedField |
||||
|
{ |
||||
|
Field = nameof(FakeProtectionObject.Num3), |
||||
|
Owner = "user1", |
||||
|
Resource = resource.Resource, |
||||
|
Visitor = "", |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
var rules = new List<ProtectedFieldRule>() |
||||
|
{ |
||||
|
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<IUnitOfWorkManager>(); |
||||
|
unitOfWorkManager.Current.AddItem<ResourceGrantedResult>( |
||||
|
"ResourceGranted", |
||||
|
new ResourceGrantedResult( |
||||
|
resource, |
||||
|
fields.ToArray(), |
||||
|
rules.ToArray())); |
||||
|
|
||||
|
var identity3 = new ClaimsIdentity(); |
||||
|
identity3.AddClaim(new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString())); |
||||
|
identity3.AddClaim(new Claim(AbpClaimTypes.UserName, "user3")); |
||||
|
identity3.AddClaim(new Claim(AbpClaimTypes.Role, "role3")); |
||||
|
using (_accessor.Change(identity3)) |
||||
|
{ |
||||
|
var result = await _repository.GetListAsync(); |
||||
|
result.Count.ShouldBe(0); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,59 +1,59 @@ |
|||||
using Microsoft.Extensions.DependencyInjection; |
using Microsoft.Extensions.DependencyInjection; |
||||
using System; |
using System; |
||||
using System.Threading.Tasks; |
using System.Threading.Tasks; |
||||
using Volo.Abp; |
using Volo.Abp; |
||||
using Volo.Abp.Modularity; |
using Volo.Abp.Modularity; |
||||
using Volo.Abp.Testing; |
using Volo.Abp.Testing; |
||||
using Volo.Abp.Uow; |
using Volo.Abp.Uow; |
||||
|
|
||||
namespace LINGYUN.Abp.Tests |
namespace LINGYUN.Abp.Tests |
||||
{ |
{ |
||||
public abstract class AbpTestsBase<TStartupModule> : AbpIntegratedTest<TStartupModule> |
public abstract class AbpTestsBase<TStartupModule> : AbpIntegratedTest<TStartupModule> |
||||
where TStartupModule : IAbpModule |
where TStartupModule : IAbpModule |
||||
{ |
{ |
||||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
||||
{ |
{ |
||||
options.UseAutofac(); |
options.UseAutofac(); |
||||
} |
} |
||||
|
|
||||
protected virtual Task WithUnitOfWorkAsync(Func<Task> func) |
protected virtual Task WithUnitOfWorkAsync(Func<Task> func) |
||||
{ |
{ |
||||
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
||||
} |
} |
||||
|
|
||||
protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func<Task> action) |
protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func<Task> action) |
||||
{ |
{ |
||||
using (var scope = ServiceProvider.CreateScope()) |
using (var scope = ServiceProvider.CreateScope()) |
||||
{ |
{ |
||||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
||||
|
|
||||
using (var uow = uowManager.Begin(options)) |
using (var uow = uowManager.Begin(options)) |
||||
{ |
{ |
||||
await action(); |
await action(); |
||||
|
|
||||
await uow.CompleteAsync(); |
await uow.CompleteAsync(); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|
||||
protected virtual Task<TResult> WithUnitOfWorkAsync<TResult>(Func<Task<TResult>> func) |
protected virtual Task<TResult> WithUnitOfWorkAsync<TResult>(Func<Task<TResult>> func) |
||||
{ |
{ |
||||
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
||||
} |
} |
||||
|
|
||||
protected virtual async Task<TResult> WithUnitOfWorkAsync<TResult>(AbpUnitOfWorkOptions options, Func<Task<TResult>> func) |
protected virtual async Task<TResult> WithUnitOfWorkAsync<TResult>(AbpUnitOfWorkOptions options, Func<Task<TResult>> func) |
||||
{ |
{ |
||||
using (var scope = ServiceProvider.CreateScope()) |
using (var scope = ServiceProvider.CreateScope()) |
||||
{ |
{ |
||||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
||||
|
|
||||
using (var uow = uowManager.Begin(options)) |
using (var uow = uowManager.Begin(options)) |
||||
{ |
{ |
||||
var result = await func(); |
var result = await func(); |
||||
await uow.CompleteAsync(); |
await uow.CompleteAsync(); |
||||
return result; |
return result; |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
Loading…
Reference in new issue