WCF 的问题 + NTLM 身份验证和负载平衡
再次尝试让我的 WCF 服务在我们的负载平衡环境中工作,我一直充满希望。我已开始使用
因为 建议是设置keepAliveEnabled
指令。
也就是说,我在服务器端设置 Windows 身份验证时遇到问题,因为
似乎没有以相同的方式运行。
服务器端看起来像这样:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<bindings>
<customBinding>
<binding name="HttpBinding" closeTimeout="00:00:45">
<textMessageEncoding>
<readerQuotas maxStringContentLength="200000" maxArrayLength="200000" />
</textMessageEncoding>
<httpTransport keepAliveEnabled="false" maxReceivedMessageSize="200000" authenticationScheme="Negotiate"/>
</binding>
</customBinding>
</bindings>
<services>
<endpoint address="http://svcserv/Services/ReportService/Reports.svc" binding="customBinding"
bindingConfiguration="HttpBinding" contract="ReportService.IReports" >
</endpoint>
<endpoint address="mex" binding="customBinding" bindingConfiguration="HttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ReportService.ReportsBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
客户端看起来像这样:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<bindings>
<basicHttpBinding>
<binding name="CustomBinding_IReports" maxReceivedMessageSize="200000">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="CustomBinding_IReports" address="http://omsnetdev/Services/ReportService/Reports.svc"
binding="basicHttpBinding" bindingConfiguration="CustomBinding_IReports" contract="ReportService.IReports">
<identity>
<servicePrincipalName value="host/svcserv"/>
<dns value="svcserv"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
如果我将authenticationScheme 设置为“Negotiate”,那么我会收到类似于 SOAP header Action was notunderstand.
的内容。 或者,有一点,客户端发现响应内容类型为“”,但预期为“application/soap+xml”。
如果我将authenticationScheme更改为“Ntlm”,那么我会收到异常:请求失败,HTTP状态401:未经授权。
但我相信这是由于协商失败(由于 SPN 值?),因此它回退到“Ntlm”并失败。
我会将此作为 IIS 服务器上的配置注销,但我已经验证了这些设置。
Once again attempting to get my WCF service working in our load balanced environment and I've been hopeful. I've moved on to using a <customBinding>
since it appears that the recommendation is to set the keepAliveEnabled
directive.
That said, I am having a problem setting up Windows authentication on the server side since the <customBinding>
does not seem to function in the same way.
The server side looks like this:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<bindings>
<customBinding>
<binding name="HttpBinding" closeTimeout="00:00:45">
<textMessageEncoding>
<readerQuotas maxStringContentLength="200000" maxArrayLength="200000" />
</textMessageEncoding>
<httpTransport keepAliveEnabled="false" maxReceivedMessageSize="200000" authenticationScheme="Negotiate"/>
</binding>
</customBinding>
</bindings>
<services>
<endpoint address="http://svcserv/Services/ReportService/Reports.svc" binding="customBinding"
bindingConfiguration="HttpBinding" contract="ReportService.IReports" >
</endpoint>
<endpoint address="mex" binding="customBinding" bindingConfiguration="HttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ReportService.ReportsBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
The client side looks like this:
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<bindings>
<basicHttpBinding>
<binding name="CustomBinding_IReports" maxReceivedMessageSize="200000">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"/>
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint name="CustomBinding_IReports" address="http://omsnetdev/Services/ReportService/Reports.svc"
binding="basicHttpBinding" bindingConfiguration="CustomBinding_IReports" contract="ReportService.IReports">
<identity>
<servicePrincipalName value="host/svcserv"/>
<dns value="svcserv"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
If I leave the authenticationScheme set to "Negotiate" then I receive something along the lines of either SOAP header Action was not understood.
or, at one point, Client found response content type of '', but expected 'application/soap+xml'.
If I change the authenticationScheme to "Ntlm" then I receive Exception: The request failed with HTTP status 401: Unauthorized.
but I believe this is due to the negotiation failing (due to the SPN value?) so it falls back to "Ntlm" and fails.
I would write this off as a configuration on the IIS server but I have verified the settings.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我相信这不仅仅是 WCF 问题,而且是一个概念模型。您希望实现完全无状态的方案,但同时需要对身份验证进行有状态处理,因为 NTLM(并且没有其他传输级别身份验证)是在单个请求响应中执行的。
以下是握手工作原理的简短描述:
此握手必须使用单个负载平衡服务器执行,但是一旦关闭持久 HTTP 连接,您将强制客户端为每个调用打开新的 TCP 连接,并且每个调用都单独进行负载平衡。这很可能会以这些调用传递到不同的服务器而结束 =>认证失败。简而言之,您需要:
I belief this is not only WCF problem but a conceptual model. You want to make completely stateless scenario but in the same time you need stateful handling of authentication because NTLM (and no other transport level authentication) is performed within single request response.
Here is short description how the handshake works:
This handshake must be performed with single load balanced server but once you turn off persistent HTTP connections you will force your client to open new TCP connection for each call and each call is load balanced separately. That will most probably ends with these calls passed to different servers => authentication failed. In short you need either:
如果您遇到与 SPN 相关的问题,请参阅此答案:SO WCF-Security-Problem 问题
使用负载均衡器时,您应该遇到的唯一问题是您是否需要会话保持对一台主机的“粘性”。对于给定的会话,如果您配置正确,负载均衡器应该能够为您执行此操作。
请注意,如果服务器和客户端位于同一台计算机上,Windows 服务器具有不使用 SSPI 的后备模式。当您从测试转向产品时,这会让您感到焦灼。
If you have a problem related to the SPN, please see this answer: SO WCF-Security-Problem question
The only issue you should have with the load balancer is whether you need your session to remain "sticky" to one host. For a given session the load balancer should be able to do this for you if you configure it correctly.
Note that windows server has a fallback mode that does not use SSPI if you have the server and client on the same machine. This lets you get burnt when you move from test to prod.