问题描述
我有一个 ASP.NET Web API 服务,它在启用了 Windows 身份验证的 Web 服务器上运行.
I have an ASP.NET Web API service that runs on a web server with Windows Authentication enabled.
我有一个基于 MVC4 的客户端站点,该站点运行在同一 Web 服务器上的不同站点中,该站点使用 HttpClient 从服务中提取数据.此客户端站点在启用身份模拟的情况下运行,并且还使用 Windows 身份验证.
I have a client site built on MVC4 that runs in a different site on the same web server that uses the HttpClient to pull data from the service. This client site runs with identity impersonation enabled and also uses windows authentication.
Web 服务器是带有 IIS 7.5 的 Windows Server 2008 R2.
The web server is Windows Server 2008 R2 with IIS 7.5.
我面临的挑战是让 HttpClient 作为其身份验证过程的一部分传递当前 Windows 用户.我以这种方式配置了 HttpClient:
The challenge I am having is getting the HttpClient to pass the current windows user as part of its authentication process. I have configured the HttpClient in this manner:
var clientHandler = new HttpClientHandler();
clientHandler.UseDefaultCredentials = true;
clientHandler.PreAuthenticate = true;
clientHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
var httpClient = new HttpClient(clientHandler);
我的理解是,在启用身份模拟的情况下运行站点,然后以这种方式构建客户端应该会导致客户端使用当前登录用户的模拟身份对服务进行身份验证.
My understanding is that running the site with identity impersonation enabled and then building the client in this manner should result in the client authenticating to the service using the impersonated identity of the currently logged in user.
这不会发生.事实上,客户端似乎根本没有进行身份验证.
This is not happening. In fact, the client doesn't seem to be authenticating at all.
该服务被配置为使用 Windows 身份验证,这似乎完美地工作.我可以在我的网络浏览器中访问 http://server/api/shippers 并被提示进行 Windows 身份验证,一次输入我收到请求的数据.
The service is configured to use windows authentication and this seems to work perfectly. I can go to http://server/api/shippers in my web browser and be prompted for windows authentication, once entered I receive the data requested.
在 IIS 日志中,我看到 API 请求在未经身份验证的情况下收到并收到 401 质询响应.
In the IIS logs I see the API requests being received with no authentication and receiving a 401 challenge response.
关于这个的文档似乎很少.
Documentation on this one seems to be sparse.
我需要深入了解可能出错的地方或在此应用程序中使用 Windows 身份验证的其他方法.
I need some insight into what could be wrong or another way to use windows authentication with this application.
谢谢,克雷格
推荐答案
我已经调查了 HttpClientHandler 的源代码(我能够得到的最新版本),这是可以在 SendAsync 方法中找到的:
I have investigated the source code of HttpClientHandler (the latest version I was able to get my hands on) and this is what can be found in SendAsync method:
// 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 进程的凭据(而不是模拟用户的凭据)执行.
Now if you check within your code the value of SecurityContext.IsWindowsIdentityFlowSuppressed() you will most probably get true. In result the StartRequest method is executed in new thread with the credentials of the asp.net process (not the credentials of the impersonated user).
有两种可能的方法.如果你有权访问你的服务器 aspnet_config.config,你应该设置以下设置(在 web.config 中设置似乎没有效果):
There are two possible ways out of this. If you have access to yours server aspnet_config.config, you should set following settings (setting those in web.config seems to have no effect):
<legacyImpersonationPolicy enabled="false"/>
<alwaysFlowImpersonationPolicy enabled="true"/>
如果您无法更改 aspnet_config.config,则必须创建自己的 HttpClientHandler 来支持这种情况.
If you can't change the aspnet_config.config you will have to create your own HttpClientHandler to support this scenario.
关于 FQDN 使用的更新
您在此处遇到的问题是 Windows 中的一项功能,旨在防止反射攻击".要解决此问题,您需要在尝试访问服务器的计算机上将您尝试访问的域列入白名单.请按照以下步骤操作:
The issue you have hit here is a feature in Windows that is designed to protect against "reflection attacks". To work around this you need to whitelist the domain you are trying to access on the machine that is trying to access the server. Follow below steps:
- 转到开始 --> 运行 --> regedit
- 找到
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlLsaMSV1_0
注册表项. - 右键单击它,选择新建,然后选择多字符串值.
- 输入
BackConnectionHostNames
(ENTER). - 右键单击刚刚创建的值并选择修改.
- 将本地计算机上站点的主机名放入值框中,然后单击确定(每个主机名/FQDN 都需要在自己的行上,没有通配符,名称必须完全匹配).
- 保存一切并重启机器
- Go to Start --> Run --> regedit
- Locate
HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlLsaMSV1_0
registry key. - Right-click on it, choose New and then Multi-String Value.
- Type
BackConnectionHostNames
(ENTER). - Right-click just created value and choose Modify.
- Put the host name(s) for the site(s) that are on the local computer in the value box and click OK (each host name/FQDN needs to be on it's own line, no wildcards, the name must be exact match).
- Save everything and restart the machine
您可以在此处阅读有关该问题的完整知识库文章.
You can read full KB article regarding the issue here.
这篇关于无法使用 HttpClient 对 ASP.NET Web Api 服务进行身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!