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 System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Testing; |
|||
using Volo.Abp.Uow; |
|||
|
|||
namespace LINGYUN.Abp.Tests |
|||
{ |
|||
public abstract class AbpTestsBase<TStartupModule> : AbpIntegratedTest<TStartupModule> |
|||
where TStartupModule : IAbpModule |
|||
{ |
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
|
|||
protected virtual Task WithUnitOfWorkAsync(Func<Task> func) |
|||
{ |
|||
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
|||
} |
|||
|
|||
protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func<Task> action) |
|||
{ |
|||
using (var scope = ServiceProvider.CreateScope()) |
|||
{ |
|||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
|||
|
|||
using (var uow = uowManager.Begin(options)) |
|||
{ |
|||
await action(); |
|||
|
|||
await uow.CompleteAsync(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected virtual Task<TResult> WithUnitOfWorkAsync<TResult>(Func<Task<TResult>> func) |
|||
{ |
|||
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
|||
} |
|||
|
|||
protected virtual async Task<TResult> WithUnitOfWorkAsync<TResult>(AbpUnitOfWorkOptions options, Func<Task<TResult>> func) |
|||
{ |
|||
using (var scope = ServiceProvider.CreateScope()) |
|||
{ |
|||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
|||
|
|||
using (var uow = uowManager.Begin(options)) |
|||
{ |
|||
var result = await func(); |
|||
await uow.CompleteAsync(); |
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.Testing; |
|||
using Volo.Abp.Uow; |
|||
|
|||
namespace LINGYUN.Abp.Tests |
|||
{ |
|||
public abstract class AbpTestsBase<TStartupModule> : AbpIntegratedTest<TStartupModule> |
|||
where TStartupModule : IAbpModule |
|||
{ |
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
|
|||
protected virtual Task WithUnitOfWorkAsync(Func<Task> func) |
|||
{ |
|||
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
|||
} |
|||
|
|||
protected virtual async Task WithUnitOfWorkAsync(AbpUnitOfWorkOptions options, Func<Task> action) |
|||
{ |
|||
using (var scope = ServiceProvider.CreateScope()) |
|||
{ |
|||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
|||
|
|||
using (var uow = uowManager.Begin(options)) |
|||
{ |
|||
await action(); |
|||
|
|||
await uow.CompleteAsync(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
protected virtual Task<TResult> WithUnitOfWorkAsync<TResult>(Func<Task<TResult>> func) |
|||
{ |
|||
return WithUnitOfWorkAsync(new AbpUnitOfWorkOptions(), func); |
|||
} |
|||
|
|||
protected virtual async Task<TResult> WithUnitOfWorkAsync<TResult>(AbpUnitOfWorkOptions options, Func<Task<TResult>> func) |
|||
{ |
|||
using (var scope = ServiceProvider.CreateScope()) |
|||
{ |
|||
var uowManager = scope.ServiceProvider.GetRequiredService<IUnitOfWorkManager>(); |
|||
|
|||
using (var uow = uowManager.Begin(options)) |
|||
{ |
|||
var result = await func(); |
|||
await uow.CompleteAsync(); |
|||
return result; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue