c# - 使用 EFCore 拦截器实现行级安全
问题描述
我有一个多租户 PostgreSQL 数据库,它使用行级安全性来控制租户应该能够看到的内容。
我正在使用 EF Core 和 ASP.NET Core 来访问这个数据库。为了处理租户访问,我使用连接拦截器来运行适当的数据库命令。例如:
为此,我创建了一个连接拦截器。
public override async Task ConnectionOpenedAsync(
DbConnection connection,
ConnectionEndEventData eventData,
CancellationToken cancellationToken = default)
{
using var command = connection.CreateCommand();
var commandText = string.Join("\r\n",
"SET SESSION ROLE TO tenant;",
$"SET SESSION tenant.userId TO '{this.userId}';");
command.CommandText = commandText;
await command.ExecuteNonQueryAsync(cancellationToken);
await base.ConnectionOpenedAsync(connection, eventData, cancellationToken);
}
所有这些都可以正常工作,但我还需要在非租户上下文中访问数据库。换句话说,我不希望上面的拦截器总是运行。
我正在努力寻找最好的方法来做到这一点。我最初的尝试是使用接口来定义租户或“全局”接口
// (MyDbContext implements both IMyTenantDbContext and IMyGlobalDbContext)
services.AddDbContext<IMyTenantDbContext, MyDbContext>((sp, options) =>
{
var tenantInterceptor = sp.GetRequiredService<SetTenantConnectionInterceptor>();
options
.UseNpgsql(connectionString)
.AddInterceptors(tenantInterceptor);
});
services.AddDbContext<IMyGlobalDbContext, MyDbContext>(options =>
{
options
.UseNpgsql(connectionString);
});
但是由于某种原因,DI 系统使用第一个 AddDbContext,即使我尝试注入一个IMyGlobalDbContext
含义,拦截器仍在使用中。
我确信必须有更好的方法来做到这一点,所以如果我做的完全错误,请告诉我。
解决方案
我建议将其设置为 userId 可以为 null 或“系统” userId,这意味着不运行拦截器代码,因此同一个拦截器可以处理这两种情况。
推荐阅读
- typescript - Redux 如何生成它们的类型?
- angular - 如果 next.handle 返回 401(未授权),则 httpinterceptor 中的异步更新令牌
- php - 单页上的两个表单,一个在 laravel 中不起作用
- go - 在测试中调用“stty size”会产生“Inappropriate ioctl for device”错误,如何解决?
- google-api - 是否有用于在 G Suite 中创建或管理自定义目录的 API?
- javascript - Javascript Fetch 偶尔返回 404
- sql - 对多个左连接求和
- unity3d - 如何使用 MRTK v2 C# 输入点击事件
- javascript - 在我的代码中找不到 1/10^n 函数的问题
- c++ - libgit2:git_clone() 失败并出现“无法创建 ssl 对象”错误