[英]Problem with WCF + NTLM authentication and load balancing
Once again attempting to get my WCF service working in our load balanced environment and I've been hopeful. 再次尝试使我的WCF服务在负载平衡的环境中工作,我一直抱有希望。 I've moved on to using a
<customBinding>
since it appears that the recommendation is to set the keepAliveEnabled
directive. 我继续使用
<customBinding>
因为看来建议是设置keepAliveEnabled
指令。
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. 就是说,由于
<customBinding>
似乎无法以相同的方式运行,因此在服务器端设置Windows身份验证时遇到了问题。
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.
如果我将authenticationScheme设置为“ Negotiate”,那么我将沿任一
SOAP header Action was not understood.
收到类似的消息SOAP header Action was not understood.
or, at one point, Client found response content type of '', but expected 'application/soap+xml'.
或者,某一时刻,
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.
如果我将authenticationScheme更改为“ Ntlm”,则会收到
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. 但是我认为这是由于协商失败( 由于SPN值? ) 导致的,因此回退到“ Ntlm”并失败了。
I would write this off as a configuration on the IIS server but I have verified the settings. 我将其注销为IIS服务器上的配置,但已验证了设置。
I belief this is not only WCF problem but a conceptual model. 我相信这不仅是WCF问题,而且是概念模型。 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.
您希望创建完全无状态的方案,但是同时您需要对认证进行有状态的处理,因为NTLM(并且没有其他传输级别的认证)是在单个请求响应中执行的。
Here is short description how the handshake works: 这是握手的简短说明:
Client Server
-----------------------------------------------------------------------------------------
Send initial request ---------------------------->
<---------------------------- Returns 401 with WWW-Authenticate
header demanding NTLM
Sends empty request ---------------------------->
with Authorization
header with initial
token
<---------------------------- Returns 401 with WWW-Authenticate
header containing some server token
Sends request with ---------------------------->
Authorization header
with final token
<---------------------------- Returns 200 and expected response
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. 此握手必须在单个负载平衡服务器上执行,但是一旦关闭持久HTTP连接,您将强制客户端为每个调用打开新的TCP连接,并且每个调用将分别进行负载平衡。 That will most probably ends with these calls passed to different servers => authentication failed.
这很可能以将这些调用传递到其他服务器而结束=>身份验证失败。 In short you need either:
简而言之,您需要:
If you have a problem related to the SPN, please see this answer: SO WCF-Security-Problem question 如果您有与SPN相关的问题,请参见以下答案: SO WCF-Security-Problem问题
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. 请注意,如果服务器和客户端在同一台计算机上,则Windows服务器具有不使用SSPI的后备模式。 This lets you get burnt when you move from test to prod.
当您从测试转移到产品时,这会让您感到沮丧。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.