除非客户端和服务器使用相同的windows标识,否则带有sspi的WCF Net.tcp将失败

除非客户端和服务器使用相同的windows标识,否则带有sspi的WCF Net.tcp将失败,wcf,security,net.tcp,sspi,Wcf,Security,Net.tcp,Sspi,我有一个由windows服务托管的WCF服务。如果我使用与服务运行时使用的凭据相同的凭据登录到客户端计算机,则客户端应用程序将成功,但如果我使用任何其他有效域帐户登录,则客户端应用程序将失败,出现异常 我有两个我正在测试的帐户,一个是普通用户帐户,另一个是管理员帐户。我尝试了下面列出的四种组合: Server account CLient RegUser AdminAcct RegUser Succeeds

我有一个由windows服务托管的WCF服务。如果我使用与服务运行时使用的凭据相同的凭据登录到客户端计算机,则客户端应用程序将成功,但如果我使用任何其他有效域帐户登录,则客户端应用程序将失败,出现异常

我有两个我正在测试的帐户,一个是普通用户帐户,另一个是管理员帐户。我尝试了下面列出的四种组合:

                   Server account
   CLient      RegUser    AdminAcct   
  RegUser     Succeeds      Fails   
 AdminAcct     Fails       Succeeds    
正如您所看到的,当客户端和服务器都在非管理员帐户下运行时,系统工作时,这不可能是管理员问题。 在两种失败的情况下,我都会在客户端上得到相同的异常,服务器日志中没有任何发生的迹象:

“调用SSPI失败。请参阅内部异常”

内部异常是“目标原则名称不正确。”

我已将帐户注册为SPN

该问题仅在我的客户端应用程序中出现,但在使用Visual Studio附带的
WCVFTestClient.exe
时不会出现

WCF跟踪日志中的异常为

“System.ServiceModel.Security.SecurityNegotiationException, System.ServiceModel,版本=4.0.0.0,区域性=中性, PublicKeyToken=b77a5c561934e089“

带着一条信息:

“远程端的身份验证失败(流可能仍可用于其他身份验证尝试)。”

堆栈跟踪位于底部: 怎么了

堆栈跟踪


System.ServiceModel.Channel.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeAcceptor.OnAcceptUpgrade(流 流、SecurityMessageProperty和remoteSecurity) System.ServiceModel.Channel.StreamSecurityUpgradeAcceptorBase.AcceptUpgrade(流 (溪流) System.ServiceModel.Channel.InitialServerConnectionReader.UpgradeConnection(IConnection 连接,StreamUpgradeAcceptor upgradeAcceptor, IDEFaultCommunicationTimeout(默认超时) System.ServiceModel.Channel.ServerSessionPreambleConnectionReader.ServerFramingDuplexSessionChannel.OnOpen(TimeSpan 超时) System.ServiceModel.Channel.CommunicationObject.Open(时间跨度 超时) System.ServiceModel.Dispatcher.ChannelHandler.openAndensureUpp() System.Runtime.ActionItem.DefaultActionItem.TraceAndInvoke() System.Runtime.ActionItem.CallbackHelper.InvokeWithoutContext(对象 (州) System.Runtime.IOThreadScheduler.ScheduledOrlApped.IOCallback(UInt32 错误代码,UInt32个字节,NativeOverlapped*NativeOverlapped) System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32 错误,UInt32字节读取,NativeOverlapped*NativeOverlapped) System.Threading.\u IOCompletionCallback.PerformiCompletionCallback(UInt32 错误代码,UInt32个字节,本机重叠*pOVERLAP)


找到了答案。我的问题是两个因素的结合

  • 使用net.tcp二进制WCF协议时,客户端安全模式确定是使用NTLM还是Kerberos进行身份验证。如果将客户端安全模式设置为“传输”,则身份验证将使用NTLM,并且只能进行一个跃点。如果您试图让WCF服务器与第三台服务器(如数据库)通信,它将失败。使用SecurityMode=“Message”,otoh会导致WCF服务器使用Kerberos,这允许多跳

  • 第二个问题与我在绑定中对客户机所做的工作有关。WCF protocol net.tcp要求在客户端上实例化端点时,必须指定“端点标识”(请参阅下面的代码)。我错误地认为这与身份验证有关,因此是客户端上当前登录用户(Windows主体)的身份

        var epId = EndpointIdentity.CreateUpnIdentity(userPrincipalName);
        var ep = new EndpointAddress(new Uri(url), epId):
    
    不。。。在客户端上创建端点时必须指定的标识必须是服务器正在运行的标识。这就是为什么每当我使用运行服务的同一用户登录到客户端时,代码都会工作,而当客户端是另一个用户时,代码就会失败

    我仍然不明白为什么必须在客户端的端点中指定(服务帐户的)此用户标识。服务器上的哪些功能需要此数据


  • 关于第二点,客户端不需要在服务器的同一Windows帐户下运行才能成功进行身份验证,也不需要在请求中手动指定帐户名。据我所知,WCF身份验证是相互的,这意味着客户端也在验证服务器


    您收到的错误可能是由于客户端出现故障。如果您将客户端的服务端点配置为提供ServicePrincipalName,那么问题很可能会得到解决。我发现解决我遇到的相同问题非常有帮助。

    非常感谢您的回答。经过一个又一个小时的尝试和错误,我尝试了这个解决方案,它就像一个魅力!如果我们再见面,我会给你一杯啤酒;-)不客气!我去哪里买啤酒?根据你的个人资料,我想我们在不久的将来不会再见面了……但永无止境的感谢将伴随着你;-)#这是失败的主要原因。使用Windows身份验证时,还将验证服务器的标识。如果您以系统或网络服务的形式运行服务,它可以访问机器SPN,您不需要显式地提供UPN,因为它默认为机器SPN。由于您正在运行一个自定义帐户,您需要告知您的客户,以便它能够对服务器进行身份验证#1说您需要消息安全性才能与数据库通信是错误的,因为这些通信没有使用WCF。它可能有触发Kerberos的副作用,这可能是您的一个问题。强制Kerberos的更好方法是将AllowNtlm设置为false(google it)。链接无效