- ABP Framework version: v7.3.3
- UI Type: Blazor Server
- Database System: EF Core SQL Server
- Tiered (for MVC) or Auth Server Separated (for Angular): yes
- Exception message and full stack trace:
- Steps to reproduce the issue:
Inspired by this documentation.
What is the best way to enable/disable a global EF filter for particular users based on their permissions?
In this particular case, we have created a ITestData interface which domain objects can inherit from and implement bool IsTestDate { get; set; }
that states whether a particular line in the database is test data or not. Used in some tests we have in production. Like so:
class SomeUserData : FullyAuditedEntity, ITestData
{
public string UserData1 { get; set; }
public string UserData2 { get; set; }
public bool IsTestData { get; set; } = true; // <- come from ITestData
}
We don't want regular users to see this test data, so we want to tie it with a permission.
We do that by creating a middleware that enables/disables the ITestData EF global filter if the user has or doesn't have the permission assigned respectively.
public class TestDataPermissionMiddleware : IMiddleware, IScopedDependency
{
private readonly ILogger<TestDataPermissionMiddleware> _logger;
private readonly IAuthorizationService _authorizationService;
private readonly IDataFilter<ITestData> _dataFilter;
public TestDataPermissionMiddleware(ILogger<TestDataPermissionMiddleware> logger, IAuthorizationService authorizationService, IDataFilter<ITestData> dataFilter)
{
_logger = logger;
_authorizationService = authorizationService;
_dataFilter = dataFilter;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
bool granted = await _authorizationService.IsGrantedAsync(SharedEntitiesPermissions.TestDataAccess.Default);
if (!granted)
_dataFilter.Enable();
else
_dataFilter.Disable();
}
catch (Exception ex)
{
_logger?.LogError(ex, "TestDataPermissionMiddleware: Error occurred.");
}
await next(context);
}
}
Here is the data filter code:
protected bool IsTestDataFilterEnabled => DataFilter?.IsEnabled<ITestData>() ?? true;
protected override bool ShouldFilterEntity<TEntity>(IMutableEntityType entityType)
{
if (typeof(ITestData).IsAssignableFrom(typeof(TEntity)))
{
return true;
}
return base.ShouldFilterEntity<TEntity>(entityType);
}
protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
{
var expression = base.CreateFilterExpression<TEntity>();
if (typeof(ITestData).IsAssignableFrom(typeof(TEntity)))
{
Expression<Func<TEntity, bool>> isTestDataFilter = e => !IsTestDataFilterEnabled || !EF.Property<bool>(e, nameof(ITestData.IsTestData));
expression = expression == null
? isTestDataFilter
: CombineExpressions(expression, isTestDataFilter);
}
return expression;
}
It works fine, but I was wondering if there is a better way of doing this that you could recommend?
1 Answer(s)
-
0
hi
You can add permission claims to the current user and then get the claim in the EF Core DB context. This will be easier.
But this requires a dynamic claims system if you deny permission from a user.
https://abp.io/docs/latest/framework/fundamentals/authorization?_redirected=B8ABF606AA1BDF5C629883DF1061649A#claims-principal-factory https://abp.io/docs/latest/framework/fundamentals/dynamic-claims?_redirected=B8ABF606AA1BDF5C629883DF1061649A