39

我有一个在启用了 Windows 身份验证的 Web 服务器上运行的 ASP.NET Web API 服务。

我有一个基于 MVC4 构建的客户端站点,该站点在使用 HttpClient 从服务中提取数据的同一 Web 服务器上的不同站点中运行。此客户端站点在启用身份模拟的情况下运行,并且还使用 Windows 身份验证。

Web 服务器是带有 IIS 7.5 的 Windows Server 2008 R2。

我面临的挑战是让 HttpClient 将当前 Windows 用户作为其身份验证过程的一部分传递。我以这种方式配置了 HttpClient:

var clientHandler = new HttpClientHandler();
clientHandler.UseDefaultCredentials = true;
clientHandler.PreAuthenticate = true;
clientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
var httpClient = new HttpClient(clientHandler);

我的理解是,在启用身份模拟的情况下运行站点,然后以这种方式构建客户端应该会导致客户端使用当前登录用户的模拟身份对服务进行身份验证。

这没有发生。事实上,客户端似乎根本没有进行身份验证。

该服务配置为使用 Windows 身份验证,这似乎工作得很好。我可以在我的网络浏览器中访问http://server/api/shippers并被提示进行 Windows 身份验证,一旦进入我就会收到请求的数据。

在 IIS 日志中,我看到在没有身份验证的情况下收到 API 请求并收到 401 质询响应。

关于这个的文档似乎很少。

我需要深入了解在此应用程序中使用 Windows 身份验证可能出现的问题或其他方式。

谢谢你,克雷格

4

4 回答 4

34

我调查了 HttpClientHandler 的源代码(我能够得到的最新版本),这可以在 SendAsync 方法中找到:

// BeginGetResponse/BeginGetRequestStream have a lot of setup work to do before becoming async
// (proxy, dns, connection pooling, etc).  Run these on a separate thread.
// Do not provide a cancellation token; if this helper task could be canceled before starting then 
// nobody would complete the tcs.
Task.Factory.StartNew(startRequest, state);

现在,如果您在代码中检查 SecurityContext.IsWindowsIdentityFlowSuppressed() 的值,您很可能会得到正确的结果。结果,StartRequest 方法使用 asp.net 进程的凭据(不是模拟用户的凭据)在新线程中执行。

有两种可能的方法。如果您有权访问您的服务器 aspnet_config.config,则应设置以下设置(在 web.config 中设置这些设置似乎没有效果):

<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>

如果您无法更改 aspnet_config.config,则必须创建自己的 HttpClientHandler 来支持这种情况。

关于 FQDN 使用的更新

您在此处遇到的问题是 Windows 中旨在防止“反射攻击”的功能。要解决此问题,您需要在尝试访问服务器的计算机上将您尝试访问的域列入白名单。请按照以下步骤操作:

  1. 转到开始 --> 运行 --> regedit
  2. 找到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0注册表项。
  3. 右键单击它,选择New,然后选择Multi-String Value
  4. 键入BackConnectionHostNames( ENTER )。
  5. 右键单击刚刚创建的值并选择Modify
  6. 将本地计算机上站点的主机名放入值框中,然后单击确定(每个主机名/FQDN 需要在自己的行上,没有通配符,名称必须完全匹配) .
  7. 保存所有内容并重新启动机器

您可以在此处阅读有关该问题的完整知识库文章。

于 2012-04-25T08:14:06.997 回答
10

我也有同样的问题。感谢@tpeczek 所做的研究,我开发了以下解决方案:我没有使用 HttpClient(它创建线程并异步发送请求),而是使用了在同一个线程上发出请求的 WebClient 类。这样做使我能够将用户的身份从另一个 ASP.NET 应用程序传递给 WebAPI。

明显的缺点是这不会异步工作。

var wi = (WindowsIdentity)HttpContext.User.Identity;

var wic = wi.Impersonate();
try
{
    var data = JsonConvert.SerializeObject(new
    {
        Property1 = 1,
        Property2 = "blah"
    });

    using (var client = new WebClient { UseDefaultCredentials = true })
    {
        client.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8");
        client.UploadData("http://url/api/controller", "POST", Encoding.UTF8.GetBytes(data));
    }
}
catch (Exception exc)
{
    // handle exception
}
finally
{
    wic.Undo();
}

注意:需要 NuGet 包:Newtonsoft.Json,它与 WebAPI 使用的 JSON 序列化程序相同。

于 2012-10-01T14:25:51.803 回答
0

The reason why this is not working is because you need double hop authentication.

The first hop is the web server, getting impersonation with Windows authentication to work there is no problem. But when using HttpClient or WebClient to authenticate you to another server, the web server needs to run on an account that has permission to do the necessary delegation.

See the following for more details:
http://blogs.technet.com/b/askds/archive/2008/06/13/understanding-kerberos-double-hop.aspx

Fix using the "setspn" command:
http://www.phishthis.com/2009/10/24/how-to-configure-ad-sql-and-iis-for-two-hop-kerberos-authentication-2/ (You will need sufficient access rights to perform these operations.)

Just consider what would happen if any server was allowed to forward your credentials as it pleases... To avoid this security issue, the domain controller needs to know which accounts are allowed to perform the delegation.

于 2013-03-01T14:20:08.860 回答
0

要模拟原始(经过身份验证的)用户,请在 Web.config 文件中使用以下配置:

<authentication mode="Windows" />
<identity impersonate="true" />

使用此配置,ASP.NET 始终模拟经过身份验证的用户,并且所有资源访问都使用经过身份验证的用户的安全上下文执行。

于 2016-07-11T08:24:59.203 回答