Icomm.AspNetCore.RlsElasticSearch (0.4.12.1)
Published 2025-05-20 17:40:09 +07:00 by Long Nguyễn Đình - Core
Installation
dotnet nuget add source --name ic --username your_username --password your_token https://git.icomm.vn/api/packages/ic/nuget/index.jsondotnet add package --source ic --version 0.4.12.1 Icomm.AspNetCore.RlsElasticSearchAbout this package
Hỗ trợ AspNetCore và phân quyền
Row Level Security library for Elasticsearch
INTRODUCTION
SETUP
- Register dependencies a. Register httpContextAccessor Register in Startup.cs
- HttpContextAccessor is used to retrieve user's context from current http request
services.AddHttpContextAccessor();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
b. Register UserAccessContainer
//Current user id is returned as string as generic parameter below, you can change it to int, long or Guid as if you want, but remember to change the data type in database usages as well
//TUserId is data type of user id
public class UserAccessContainer : IUserAccessContainer<TUserId>
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserAccessContainer(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
//This method is used to get user's id to inject as session context value for "SessionUserId" when creating SQL transactions to interact with sql security policies. You can modify it if you want.
public TUserId GetUserId()
{
//TODO: Your logic to get current user's context (id)
//Sample using httpContextAccessor
return _httpContextAccessor.HttpContext?.User.GetUserId() ?? throw new UnauthorizedAccessException("User not found");
}
}
c. Register GroupAccessContainer
//Current group id is returned as long as generic parameter below, you can change it to int, string or Guid as if you want, but remember to change the data type in database usages as well
//TGroupId is data type of group id
public class GroupAccessContainer : IGroupAccessContainer<TGroupId>
{
public GroupAccessContainer()
{
}
public TGroupId GetGroupId()
{
//TODO: Your logic to get current user's group
}
}
d. Register GroupHandler
//TGroupId is data type of group id
public class GroupHandler : IGroupHandler<TGroupId>
{
public bool IsAncestorOf(long groupId, long descendantGroupId)
{
//TODO: Your logic to check if groupId is ancestor of descendantGroupId
}
}
e. Set up database settings
"TestRlsOptions": {
"IndexSettings": {
"search.slowlog.threshold.fetch.warn": "1s",
"index.number_of_replicas": 1,
"index.number_of_shards": 1
},
"ConnectionSettings": {
"ConnectionType": "Static",
"Uris": [
"elas1",
"elas2",
"elas3"
]
},
"Prefix": "your_project_prefix"
}
//Configure elastic search database options in Startup.cs
services.Configure<TestRlsOptions>(Configuration.GetSection(nameof(TestRlsOptions)));
f. Register Elasticsearch connection
public interface ITestRlsManager
{
//Your connection defined here
IRlsEsCrud<TEntity, TKey, TUserId, TGroupId> Product { get; }
}
public class TestRlsManager : ITestRlsManager
{
private readonly Func<EsCrudSettings> _settings;
private readonly string _prefix;
private readonly IUserAccessContainer<TUserId> _userAccessContainer;
private readonly IGroupAccessContainer<TGroupId> _groupAccessContainer;
private readonly IGroupHandler<TGroupId> _groupHandler;
public TestRlsManager(IOptions<TestRlsOptions> options, IUserAccessContainer<TUserId> userAccessContainer, IGroupAccessContainer<TGroupId> groupAccessContainer, IGroupHandler<TGroupId> groupHandler) : this(() => options.Value.ToEsCrudSettings(), userAccessContainer, groupAccessContainer, groupHandler, options.Value.Prefix)
{
_userAccessContainer = userAccessContainer;
_groupAccessContainer = groupAccessContainer;
_prefix = options.Value.Prefix;
}
private TestRlsManager(Func<EsCrudSettings> settings, IUserAccessContainer<TUserId> userAccessContainer, IGroupAccessContainer<TGroupId> groupAccessContainer, IGroupHandler<TGroupId> groupHandler, string prefix)
{
this._settings = settings;
_userAccessContainer = userAccessContainer;
_groupAccessContainer = groupAccessContainer;
_prefix = prefix;
_groupHandler = groupHandler;
}
public IRlsEsCrud<TEntity, TKey, TUserId, TGroupId> Product => _settings.Invoke().CreateRlsEsCrud<TEntity, TKey, TUserId, TGroupId>(_prefix, _userAccessContainer, _groupAccessContainer, _groupHandler);
}
//Register DI
services.AddSingleton<ITestRlsManager, TestRlsManager>();
g. Register in repository
public class ProductRepository : EsCrudRepository<TEntity, TKey>, IProductRepository
{
private readonly ITestRlsManager _manager;
//Your connection registered above is used here
public ProductRepository(ITestRlsManager manager) : base(manager.Product)
{
_manager = manager;
}
}
h. Register rls management
//Create a class that implements RlsElasticManagementProfile
public class RegisterRlsElasticManagement : RlsElasticManagementProfile
{
public RegisterRlsElasticManagement()
{
//Register API prefix
RegisterApiPrefix(RouteConstant.PREFIX + "/v1");
//Register each candidate you want to manage rls privileges
RegisterCandidate<TEntity, TKey, TController>();
}
}
//Register rls management using the defined class above
services.AddRlsCoreElasticManagementAPI<string, long>(new RegisterRlsElasticManagement());
- Management API is now added to you TController which is controller of entity