我有一个由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,Version = 4.0.0.0,Culture = neutral, 公钥= b77a5c561934e089"
带有消息:
“远程端身份验证失败(该流可能仍可用于其他身份验证尝试)。”
堆栈跟踪位于底部: 有什么问题?
堆栈跟踪
System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeAcceptor.OnAcceptUpgrade(流 stream,SecurityMessageProperty& remoteSecurity) System.ServiceModel.Channels.StreamSecurityUpgradeAcceptorBase.AcceptUpgrade(流 流) System.ServiceModel.Channels.InitialServerConnectionReader.UpgradeConnection(IConnection 连接,StreamUpgradeAcceptor upgradeAcceptor, IDefaultCommunicationTimeouts defaultTimeouts) System.ServiceModel.Channels.ServerSessionPreambleConnectionReader.ServerFramingDuplexSessionChannel.OnOpen(时间跨度 超时) System.ServiceModel.Channels.CommunicationObject.Open(时间跨度 超时) System.ServiceModel.Dispatcher.ChannelHandler.OpenAndEnsurePump() System.Runtime.ActionItem.DefaultActionItem.TraceAndInvoke() System.Runtime.ActionItem.CallbackHelper.InvokeWithoutContext(对象 州) System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(UInt32的 errorCode,UInt32 numBytes,NativeOverlapped * nativeOverlapped) System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32的 错误,UInt32 bytesRead,NativeOverlapped * nativeOverlapped) System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32的 errorCode,UInt32 numBytes,NativeOverlapped * pOVERLAP)
答案 0 :(得分:14)
找到答案。我的问题是两个因素的结合。
使用net.tcp二进制WCF协议时,客户端安全模式确定是使用NTLM还是Kerberos进行身份验证。如果将客户端安全模式设置为“传输”,则身份验证使用NTLM,并且只能进行一次跳转。如果您尝试让WCF服务器与第三台服务器(如数据库)通信,它将失败。使用SecurityMode =“Message”,otoh,使WCF服务器使用Kerberos,允许多跳...
第二个问题与我在绑定客户端上所做的事情有关。 WCF协议net.tcp要求在客户端上实例化端点时,必须指定“端点标识”(请参阅下面的代码)。我错误地认为这与身份验证有某种关系,因此,它是客户端上当前登录用户(Windows Principal)的身份。
var epId = EndpointIdentity.CreateUpnIdentity(userPrincipalName);
var ep = new EndpointAddress(new Uri(url), epId):
否...在客户端上创建端点时必须指定的标识必须是运行服务器的标识。这就是为什么每当我使用与服务运行时相同的用户登录到客户端时代码都有效,并且当客户端是其他用户时失败。
我仍然不明白为什么必须在客户端的端点中指定(服务帐户的)用户身份。服务器上有什么功能需要这些数据?
答案 1 :(得分:1)
关于第二点,客户端不需要在服务器的同一Windows帐户下运行,以便成功进行身份验证,并且不需要在请求中手动指定帐户名称。据我所知,WCF身份验证是相互的,这意味着客户端也在验证服务器。
您收到的错误可能是由于客户端失败。如果您将客户端的服务端点配置为提供ServicePrincipalName,则问题可能会得到解决。我发现this article非常有助于解决我遇到的同样问题。