用于Windows身份的Asp.Net Core Intranet应用程序中的模拟中间件 [英] Impersonation Middleware in an Asp.Net Core Intranet app for Windows-Identity

查看:96
本文介绍了用于Windows身份的Asp.Net Core Intranet应用程序中的模拟中间件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我解释我的问题之前,这是我们的情况:

Before I explain my problem, here's our scenario:

场景

我们仅为我们的Intranet Windows用户(当前由本地Active Directory管理,但将来有可能迁移到Azure-AD)编写软件.

We write software only for our intranet Windows users (currently managed by local Active Directory but in future it is possible we migrate to Azure-AD).

到目前为止,还存在一个旧的整体式Winforms应用程序,该应用程序使用数据集直接与数据库进行通信.对数据库的所有请求均通过 WindowsIdentity (最终用户上下文)进行,因此数据库知道最终用户.

Up to yet there is an old monolithic Winforms app which communicates directly with the database using datasets. All requests to the database happens with WindowsIdentity (end-user context), so the database knows the end user.

对于将来的开发,我们希望使用Web API进行业务逻辑.仅Web应用程序应使用Entity Framework访问数据库.我们用IIS托管了带有ASP.NET Core(无状态)的Web API.因为该Web应用程序以应用程序池身份运行,所以我们编写了一个中间件,该中间件将上下文模拟给最终用户(以使数据库访问有效).

For future development we want to use a Web API for business logic. Only the web-app should access the database with Entity Framework. We wrote a Web API with ASP.NET Core (stateless) which is hosted in IIS. Because the web app runs in the app pools identity, we wrote a middleware which impersonates the context to the end-user (in order that the database access is working).

在迁移到Web服务器时,必须同时支持两个版本,因为我们无法一次迁移整个应用程序.

While migrating to the web server both versions must be supported because we cannot migrate the whole application at once.

问题

在调试环境中,Web服务器工作正常(因为没有模拟),但是在实时系统上有时服务器崩溃(并非每次都崩溃).

In debug environment the web server works fine (because there happens no impersonation) but on the live system sometimes the server crashes (not every time).

我们得到的最常见的错误是 FileLoadException ,它无法加载dll(主要是 System.Reflection ).有时,整个服务器正常运行会返回200 OK,但不包含任何http正文.

The most frequent error we get is FileLoadException which cannot load dll's (mostly System.Reflection). Other times the whole server runs without errors return 200 OK but doesn't contain any http body.

所以似乎有问题.该文档对此有一个小提示:

So it seems there is a problem. The documentation has a small hint to this:

因此在用户上下文中运行整个请求似乎不是一个好主意,但是可能是解决方案?

So run the whole request in user context seems a bad idea but would could be the solution?

我们当然要抛弃的只是模拟中间件.但是如何访问数据库?

Of course all we have to discard is the impersonation middleware. But how access the database?

选项1 :运行模拟的每个数据库调用

Option #1 : run each database call impersonated

问题

官方文档说,模拟环境中的代码被禁止运行异步事物.我们可以做到,没问题.但是我不知道实体框架是否运行异步部件?如果发生这种情况,我们的应用程序可能会再次崩溃.你有什么主意吗?

The official documentation says that code in the impersonation context is forbidden to run async things. We can do that, no problem. But I don't know if the Entity Framework runs async parts? If that would happen our app can crash again. Do you have any idea?

问题2

如果有两个请求进入asp,则会运行两个线程.是否可以同时在两个需求上调用模拟假冒?官方文档不清楚.

If two requests come in asp would run two threads. Is it allowed to call impersonation at some time async on both reqeusts? The official documentation is not so clear.

选项#2 :更改我们的数据库,因此不需要最终用户

Option #2: change our database so the end user is not required

问题

某些SQL触发器(和存储的过程)使用用户名,例如在插入时将名称写到表中.当然,我们可以更改这种行为,以便EF Core手动输入名称.

Some SQL triggers (and stored orocedures) use the user name for e.g. write the name into a table on insert. Of course we can change that behaviour so the EF Core write the name by hand.

这个问题更具有政治意义,可以找到我们为什么应将工作解决方案从 WindowsIdentity 更改为 AppIdentity 的原因.你有很好的论据吗?

This problem is more a political one to find reasons why we should change the working solution away from WindowsIdentity to an AppIdentity. Do you ahve some good arguments?

选项3 :您还有其他想法吗?

Option #3: do you have any more ideas?

我没有看到更多的解决方案,也许您呢?

I don't see more solutions, maybe you do?

顺便说一句.这是我们模拟中间件的代码:

By the way. Here is the code of our impersonation middleware:

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);
        }
    }
}

推荐答案

1.1问题::官方文档说,模拟环境中的代码被禁止运行异步事物.我们可以做到,没问题.但是我不知道EntityFramework是否运行异步部件吗?如果发生这种情况,我们的应用程序可能会再次崩溃.你有主意吗?

1.1 Question: The official documentation says that code in the impersonation context is forbidden to run async things. We can do that, no problem. But I don't know if the EntityFramework runs async parts? If that would happen our app can crash again. Have you any idea?

我实际上认为文档的这一部分已经过时和/或错误.在此之前和问题之前,一直有人要求对 RunImpersonated 进行异步重载提到传递异步功能会很好,因为模拟将在内部使用异步本地.

I actually think that this part of the documentation is outdated and/or wrong. There has been a request for an asynchronous overload for RunImpersonated before and the issue mentions that passing asynchronous functions will work fine because the impersonation will use an async local internally.

因此您可以使用 RunImpersonated ,因为这实际上是在做同一件事.文档也明确允许将其用于异步工作:

So you could use RunImpersonatedAsync for this to be super explicit, or just keep using RunImpersonated because that’s literally doing the same thing. Using it for asynchronous work is also explicitly allowed by the docs:

不同,此方法可以与async/await模式可靠地结合使用.在异步方法中,此方法的一般重载可以与异步委托参数一起使用,以便可以等待生成的任务.

This method may be used reliably with the async/await pattern, unlike Impersonate. In an async method, the generic overload of this method may be used with an async delegate argument so that the resulting task may be awaited.

我认为ASP.NET Core文档在此方面已经过时,并且打开了一个问题以使其得到纠正或澄清.

I believe that the ASP.NET Core docs are just outdated on this and opened an issue for this to get it corrected or clarified.

运行模拟的整个请求也应该可以正常工作,因此除非我在该问题中听到其他消息,否则我将假定您在应用程序中看到的崩溃可能与模拟不一样.我建议您尝试使用带有(和不带有)模拟的不同(非开发)环境分别重现此内容,以查看这是否实际上与模拟有关.至少,FileLoadException听起来不像是模拟问题,只是模拟用户可能无法访问某些加载较晚的程序集(我不确定模拟是否会在这里产生影响).

Running the whole request impersonated should also work just fine, so unless I hear something else in that issue, I would assume that the crashes you are seeing in your application might have a different reason than just impersonation. I would suggest you to try to reproduce this separately using a different (non-development) environment with and without impersonation first to see if this is actually related to the impersonation. A FileLoadException at least does not sound like an issue with impersonation, except maybe that an impersonated user could not access some assemblies that are loaded late (I’m not sure if impersonation could have an impact here).

1.2问题::如果有两个请求进入asp,则会运行两个线程.是否可以同时在两个请求上调用模拟假冒?官方文档不清楚.

1.2 Question: If two requests come in asp would run two threads. Is it allowed to call impersonation at some time async on both requests? The official documentation is not so clear.

由于模拟是使用异步本地实现的,因此模拟仅限于单个本地呼叫流.因此,使用不同的异步流的不同请求不会受到其他被模拟的影响.这也使模拟线程安全.

Since impersonation is implemented using an async local, the impersonation is restricted to a single local call flow. So a different request, using a different async flow, will not be impacted by the other being impersonated. This also makes the impersonation thread-safe.

2.1问题::某些SQL触发器(和StoredProcedures)将用户名用于例如在插入时将名称写到表中.当然,我们可以更改该行为,以便EFCore手动输入名称.

2.1 Question: Some SQL-Trigger (and StoredProcedures) use the user name for e.g. write the name into a table on insert. Of course we can change that behaviour so the EFCore write the name by hand.

是的,将用户名传递到您的查询中可能是可行的方法.

Yes, passing that username into your queries is probably the way to go.

这个问题在政治上更加棘手,可以找到我们将工作解决方案从WindowsIdentity更改为AppIdentity的原因.你有什么争论吗?

This problem is more a political one to find reasons why we should change the working solution away from WindowsIdentity to an AppIdentity. Have you some arguments?

过去也曾参与过这个项目,我可以说模仿数据库并没有真正说服我.为了使它起作用,需要授权每个用户在数据库中进行更改.这也意味着,通过直接数据库访问,用户可能会做出不允许仅使用该应用程序进行的更改.他们基本上可以绕过任何特定于应用程序的授权和保护.

Having been involved in a project in the past where this was a requirement as well, I can say that impersonating down to the database didn’t really convince me. In order for this to work, each user needs to be authorized to make changes in the database. That also means that with direct database access, users could likely make changes that they wouldn’t be allowed to do just using the application. They could basically go around any application-specific authorization and protections.

当然,用户不应该能够直接连接到数据库,但这总是会发生的.如果没有保护措施,这将变得更加关键.还请考虑那些具有管理员访问您计算机权限的用户,例如正在开发应用程序的人.默认情况下,他们确实具有访问权限,而不是没有一个可以在数据库中进行更改的帐户来限制访问,因为这就是应用程序的工作方式.

Of course, users shouldn’t be able to connect directly to the database but this can always happen. And having no protections in place then makes this just a bit more critical. Also think about those with administrator access to your machines, e.g. the ones that are developing the application. Instead of having restricted access by not having an account that could make changes in the database, they do have access by default because that’s how the application works.

在这种情况下,与只有少数用户才知道的具有有限访问权限的帐户数量有限相比,保护数据库要困难得多.

It’s a lot more difficult to protect your database in these situations compared to having a limited number of accounts with limited access that are only known to small number of users.

此外,由于您提到了向Azure AD的迁移,为了模拟您的应用程序,您的AD需要完全联合,并且应用程序服务器必须是域的一部分.因此,您必须牢记这一点.

Also, since you mentioned migration to Azure AD, in order for your application to impersonate, your AD needs to be fully federated and the application server needs to be part of the domain. So you have to keep this in mind.

并且,由于您仍依赖Windows身份验证,因此这也使身份验证更加复杂.用户必须连接到域控制器才能从NTLM中受益,否则用户将不得不每次使用其帐户数据进行身份验证.您将无法切换到其他身份验证方式,例如使用Azure AD或ADFS,这意味着您也不会从单一登录中受益.

And, since you are still relying on Windows Authentication, this also makes authentication a bit more complicated. Users will have to be connected to the domain controller in order to benefit from NTLM, otherwise they will have to authenticate themselves using their account data every time. You won’t be able to switch to alternative authentication means, e.g. using Azure AD or ADFS, meaning that you also won’t benefit from things like Single-Sign-On.

(注意:您可以使用Windows身份验证以外的其他功能,并让应用程序通过自己创建Windows身份来模拟用户.但是请相信我,您不想这样做那;这是一个配置梦night)

(Note: You can use something other than Windows Authentication, and have the application impersonate the user by creating a Windows identity itself. But trust me, you don’t want to do that; it’s a configuration nightmare)

这篇关于用于Windows身份的Asp.Net Core Intranet应用程序中的模拟中间件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆