【发布时间】:2021-04-01 02:04:23
【问题描述】:
在我解释我的问题之前,这是我们的场景:
场景
我们仅为我们的 Intranet Windows 用户编写软件(目前由本地 Active Directory 管理,但将来我们可能会迁移到 Azure-AD)。
到目前为止,还有一个旧的单体 Winforms 应用程序,它使用数据集直接与数据库通信。对数据库的所有请求都使用WindowsIdentity(最终用户上下文)进行,因此数据库知道最终用户。
对于未来的开发,我们希望将 Web API 用于业务逻辑。只有网络应用程序应该使用实体框架访问数据库。我们使用托管在 IIS 中的 ASP.NET Core(无状态)编写了一个 Web API。由于 Web 应用程序以应用程序池身份运行,因此我们编写了一个中间件来模拟最终用户的上下文(以便数据库访问正常工作)。
在迁移到 Web 服务器时,必须同时支持这两个版本,因为我们无法一次迁移整个应用程序。
问题
在调试环境中,Web 服务器工作正常(因为没有发生模拟),但在实时系统中,服务器有时会崩溃(不是每次都崩溃)。
我们得到的最常见错误是FileLoadException,它无法加载dll(主要是System.Reflection)。其他时候整个服务器运行没有错误返回 200 OK 但不包含任何 http 正文。
所以看起来有问题。该文档对此有一个小提示:
https://docs.microsoft.com/en-us/aspnet/core/security/authentication/windowsauth?view=aspnetcore-3.1#impersonation
所以在用户上下文中运行整个请求似乎是个坏主意,但可能是解决方案?
当然,我们要丢弃的只是模拟中间件。但是如何访问数据库呢?
选项#1:模拟运行每个数据库调用
问题
官方文档说模拟上下文中的代码被禁止运行异步的东西。我们可以做到,没问题。但我不知道实体框架是否运行异步部件?如果发生这种情况,我们的应用程序可能会再次崩溃。你有什么想法吗?
问题 #2
如果有两个请求进来,asp 将运行两个线程。是否允许在两个请求的某个时间异步调用模拟?官方文档不是很清楚。
选项 #2:更改我们的数据库,从而不需要最终用户
问题
一些 SQL 触发器(和存储的 orocedures)使用用户名,例如在插入时将名称写入表中。当然,我们可以更改该行为,以便 EF Core 手动编写名称。
这个问题更多地是一个政治问题,以寻找我们应该将工作解决方案从 WindowsIdentity 更改为 AppIdentity 的原因。你有什么好的论据吗?
选项#3:你还有什么想法吗?
我没有看到更多的解决方案,也许你有?
顺便说一句。下面是我们模拟中间件的代码:
public class ImpersonateMiddleware
{
private readonly RequestDelegate _next;
public ImpersonateMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var winIdent = context?.User?.Identity as WindowsIdentity;
if (winIdent == null)
{
await _next.Invoke(context).ConfigureAwait(true);
}
else
{
await WindowsIdentity.RunImpersonated(winIdent.AccessToken, async () =>
{
await _next.Invoke(context)
.ConfigureAwait(true)
;
}).ConfigureAwait(true);
}
}
}
【问题讨论】:
标签: c# entity-framework asp.net-core impersonation windows-identity