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?
Hi,
I tried using the Inject attribute and it still didn't work.
I've reproduced the error on a clean ABP Solution, here is the link: https://github.com/maksym-gryb/ABPTestSolution
Please try it out and let me know how we can resolve this issue in our codebase.
Hi,
after fumbling around with this feature management module, I found out that it was because we were changing the values via the "Editions" tab, whereas we had to change them in Tenants and use the "Manage Host Features" button.
As we didn't enable multitenancy, nor do we use it, it was rather confusing to know what to look for.
This ticket can be marked as resolved.
I've added virtual and async to the methods but the results are still the same.
As mentioned previously, the issue isn't in the feature management system itself not working, it's the fact that the feature which is set correctly in the database to "true"
Is still being read as "false" in abp via the feature checker
Hi, were you able to reproduce the issue?
Hi, were you able to replicate the issue? Or are you able to get ISettingManager in a module instantiated in an ABP solution?
I was wondering if it could be because it was a long-lived ABP solution and we did a lot of changes to it. But I created a brand new ABP Solution and created a module within that Solution and tried again and still couldn't get ISettingManagement to work in the module.
btw, I used ABP suite to create this module within the solution (both times) using this button:
reopening
Hi, I guess you've created a new module and want to use the
ISettingManager
on it, right?If so, please ensure you added the related depends on statement to your module class (ensure your domain module depends on the
AbpSettingManagementDomainModule
([DependsOn(typeof(AbpSettingManagementDomainModule))])).
That is correct, I've created a new Module using ABP Suite and want to setup Settings specifically within that module.
I've already added that dependency to the Module's Domain Module:
Check the docs before asking a question: https://docs.abp.io/en/commercial/latest/ Check the samples, to see the basic tasks: https://docs.abp.io/en/commercial/latest/samples/index The exact solution to your question may have been answered before, please use the search on the homepage.
If you're creating a bug/problem report, please include followings:
We are unable to get dependency injection of ISettingManager in the constructor of a Blazor component we created to configure the settings for a module.
The module which uses the ISettingManager is as follows:
This has worked in a separate ABP Blazor solution, but in this case we have it in a separate module in another ABP solution and when visiting the respective page we get this error: