gpt4 book ai didi

asp.net - 凭据未在生产服务器中的 WCF 调用中传递

转载 作者:行者123 更新时间:2023-12-04 21:25:08 25 4
gpt4 key购买 nike

场景

我们有一个 Web 应用程序,它使用以下代码调用 Web 服务(托管在同一台机器的 IIS 中):-

using (HttpContext.Current.Request.LogonUserIdentity.Impersonate())
{
var client = new Services.ReportFormatter(endpointName); // endpoint name is configured in config
// Services.ReportFormatter is the generated client code using svcutil
var response = client.DoWork();
}

代码的意图是使用 Web 应用程序用户的凭据执行 WCF 调用(我希望这很明显!)并且代码在 Dev 和 QA 机器上工作起来就像一个魅力。不用说,它在生产中失败了!

问题

正在生成的 .Net 异常是
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM,Basic realm="Services"'. InnerException:The remote server returned an error: (401) Unauthorized.
有趣的是,IIS 日志表明 WCF 请求中没有传递任何用户凭据
Fields: 
cs-method cs-uri-stem cs-uri-query s-port cs-username c-ip sc-status sc-substatus sc-win32-status
GET /MyWebApp/MyPage.aspx - 443 chrisf x.x.x.x
POST /MyServicesApp/ReportFormatter.svc/ntlm - 80 - x.x.x.x 401 2 2148074254
POST /MyServicesApp/ReportFormatter.svc/ntlm - 80 - x.x.x.x 401 1 0
POST /MyServicesApp/ReportFormatter.svc/ntlm - 80 - x.x.x.x 401 1 2148074252

请注意,对 Web 应用程序的请求已记录我的用户名 - 但对服务的请求未记录。将这些日志与我的开发机器上的日志进行比较,我在两个请求中都看到了我的名字 - 所以我认为这是失败的原因。

这是 WCF 配置 - 尽管它在 Dev + QA 中工作的事实让我怀疑这没有错。任何想法/帮助将不胜感激。

Web 应用程序(即 WCF 客户端)配置。
<bindings>
<basicHttpBinding>

<binding name="ReportFormatter" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:05:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="6553600" maxBufferPoolSize="524288" maxReceivedMessageSize="6553600"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true" >
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>

<client>
<endpoint binding="basicHttpBinding" bindingConfiguration="ReportFormatter" contract="Services.ReportFormatter"
name="ReportFormatter_Endpoint" address="http://localhost/MyServicesApp/ReportFormatter.svc/ntlm"/>
</client>

Web 服务应用程序的配置文件包含此
    <bindings>
<basicHttpBinding>
<binding name="BasicHttpWindowsBindingWinCred" maxReceivedMessageSize="20000000">
<readerQuotas maxStringContentLength="20000000" maxArrayLength="1000000" maxBytesPerRead="20000000" />
<security mode="TransportCredentialOnly">
<!-- clientCredentialType Windows requires IIS to be configured to support Windows authentication-->
<transport clientCredentialType="Windows" />
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpBinding>
</bindings>## Heading ##
<services>
<service behaviorConfiguration="IIS.Service1Behavior" name="Services.FormatReportImpl">
<endpoint address="ntlm" binding="basicHttpBinding" bindingConfiguration="BasicHttpWindowsBindingWinCred" name="FormatReportBindingWindowsAuthentication" contract="Services.ReportFormatter" bindingNamespace="http://www.donkey.com/Reporting" />
</service>
</services>

操作系统详情

生产:Win 2003 32bit SP2 (IIS 6.0)

质量保证:Win 2003 32 位 SP2 (IIS 6.0)

开发人员:各种!我自己的系统是 Win7 64 (IIS 7.5) - 我们在 Vista 上也有开发人员。

问题的原因和解决方法

像往常一样,魔鬼在细节中。为什么哦为什么它总是在细节中!包括血腥的细节,以防他们帮助其他有类似问题的人。

原因

为了使问题尽可能简单,我省略了 Web 应用程序和 Web 服务未托管在默认 IIS 网站中的情况。相反,它们被托管在一个单独的网站上(原因是我们在同一台服务器上托管了多个应用程序+同一个应用程序的版本),我们使用主机头信息来识别网站。

因此,生产站点(和网络服务)只能通过像“app.companyName.com”这样的 URL 访问。因此,当我说客户端 web.config 有 address="http://localhost/MyServicesApp/ReportFormatter.svc/ntlm" 时,我撒了谎。

它实际上有
address="http://app.companyName.com/MyServicesApp/ReportFormatter.svc/ntlm"
我现在觉得有点愚蠢,因为我知道我们无法跨机器边界传递 NTLM 身份验证 token - 就 WCF 客户端而言,“app.companyName.com”是一台远程机器;它不知道 DNS 将该地址映射回同一台机器 - 它可能不知道(继续阅读)。

借口

为了原谅我的愚蠢,这里有一个借口:我在问题中撒谎的原因是我已经检查过上述类型的设置在 QA 服务器上有效。我检查了以下工作在客户端的 WCF 配置地址中是否在 QA 机器上工作。
address="http://qaServerName.domainName.local/MyServicesApp/ReportFormatter.svc/ntlm"
我认为逻辑上,该地址必须转到域 DNS 才能解析,因此逻辑上将与“app.companyName.com”进行相同的处理。我什至设置了一个 DNS 别名“dnsAliasForTheQAServer”(在我们的本地域上),然后测试以下内容是否有效
address="http://dnsAliasForTheQAServer.domainName.local/MyServicesApp/ReportFormatter.svc/ntlm"
它做到了!现在您必须承认,如果机器认为它被称为“qaServerName”,那么您会认为“dnsAliasForTheQAServer.domainName.local”将被视为远程地址。所以我推断这不可能是导致生产服务器故障的问题。

只有当绝望使我们真正创建一个新的 DNS 记录(“qaServerNameDnsRecord2”)时,我们才设法在 QA 机器上重现了错误!所以我得出结论,正在 WCF 客户端和/或 DNS 上进行了一些非常聪明的名称解析,用于解析以下主机名
  • "qaServerName"
  • "qaServerName.domainName.local"
  • "dnsAliasForTheQAServer.domainName.local"

  • 到 qaServerName - 因此在逻辑上是“本地主机”(因为客户端和服务器都在同一台机器上)
    但是当主机名是
  • "qaServerNameDnsRecord2"
  • "qaServerNameDnsRecord2.domainName.local"

  • 我敢肯定,如果我对 DNS 或 Windows 如何解析名称有所了解,那么这不会让人感到意外。但我了解到,将来我不会那么快

    解决方案

    知道问题在于地址正在解析为看起来像是远程的地址,解决方案很简单 - 只需使地址看起来是本地的(如果 Web 服务托管在默认网站中,那将是 super 简单 - 只需将 address="http://localhost/..." 作为端点地址!)。

    我尝试的第一件事是编辑 QA 服务器上的主机文件,并添加一个将“app.companyName.com”映射到 127.0.0.1 的条目,但这不起作用。

    所以我做的下一件(相当不雅的)事情是为网站添加一个额外的身份,主机 header 值为 127.0.0.1然后将配置更改为 address="http://127.0.0.1/..." (我想我可以使用 localhost 而不是 127.0.0.1)。这样就解决了所有问题。

    最佳答案

    我想在生产中 WCF 和网络服务器在不同的机器上运行,而在 DEV 和 QA 中它们不是?

    您需要通过 Kerberos 身份验证委派用户身份才能模拟 WCF。原因:WCF 不知道用户凭据,因此无法正确模拟。在 Kerberos 方案中,将使用身份验证 token 而不是真正的凭据。

    如果您需要一个起点来进入 Kerberos 主题,请搜索“Kerberos IIS 委托(delegate) 2003 Windows 身份验证”或类似内容。

    关于asp.net - 凭据未在生产服务器中的 WCF 调用中传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4680943/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com