我有一个使用WIF保护的wcf服务。我正在客户端(网站)上实现令牌缓存,如Travis Spencer的博客中所述:
http://travisspencer.com/blog/2009/03/caching-tokens-to-avoid-calls.html
网站正在使用模拟(冒充我),并且STS wcf端点配置为使用Windows身份验证。
使用直接调用(即非异步调用)调用WCF服务时,令牌缓存正常工作 - 删除ClientCredentials行为并添加我的自定义CacheClientCredentials行为,并在第一次调用时缓存令牌并在后续时间重用呼叫。
但是我有一个场景,在wcf服务上调用异步方法,并提供回调。在正常情况下(非异步),CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider方法被多次调用,并且在每次调用时,线程正在运行的标识是正确的。随后对STS的调用是使用正确的凭据,用户经过身份验证并返回令牌。调用async方法时,会发生对CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider的多次调用,但只有第一次调用具有正确的标识。后续调用以“NT AUTHORITY \ NETWORK SERVICE”作为标识。因此,对STS的调用具有错误的凭据,并且身份验证失败。 (STS日志显示一条消息,指示“无法进行身份验证”。
我一直在尝试在Begin / End异步方法周围添加显式模拟,但这并不是一直有效。然后我将以下值添加到web.config:
<legacyImpersonationPolicy enabled="false" />
<alwaysFlowImpersonationPolicy enabled="true" />
这也并不总是有效(尽管有时会这样)。这里不寻常的是业务逻辑涉及3次尝试调用异步方法(如果调用失败)。我发现通常前两个失败,第三个失败,即CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider通常在前两次运行错误的身份,第三次运行正确的身份 - 但这似乎也有点随机。当CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider以正确的标识成功时,WCF调用成功。但是,令牌未添加到缓存中(不执行令牌缓存代码)后续调用非异步方法然后构造新缓存,然后获取令牌,将其添加到缓存中。
调用使用WIF保护的异步WCF方法的正确方法是什么,以确保WIF令牌在调用之间缓存?
是否需要特殊身份配置以确保在所有这些流程中使用相同的身份? (所有区域都使用模仿)
更新
我不确定它是否增加了很多,但我发现当代码不起作用时,以下是CacheClientCredentialsSecurityTokenManager中的堆栈跟踪:
Unflagged > 5732 18 Worker Thread <No Name> CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider Normal
MySecurity.dll!CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider(System.IdentityModel.Selectors.SecurityTokenRequirement tokenRequirement) Line 18
System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.AddSupportingTokenProviders(System.ServiceModel.Security.Tokens.SupportingTokenParameters supportingTokenParameters, bool isOptional, System.Collections.Generic.IList<System.ServiceModel.Security.SupportingTokenProviderSpecification> providerSpecList) + 0xca bytes
System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.OnOpen(System.TimeSpan timeout) + 0xa7 bytes
System.ServiceModel.dll!System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(System.TimeSpan timeout) + 0x45 bytes
System.ServiceModel.dll!System.ServiceModel.Security.OperationWithTimeoutAsyncResult.OnScheduled(object state) + 0x82 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke2() + 0x46 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.OnSecurityContextCallback(object o) + 0x28 bytes
mscorlib.dll!System.Security.SecurityContext.Run(System.Security.SecurityContext securityContext, System.Threading.ContextCallback callback, object state) + 0x55 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke() + 0x4d bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ProcessCallbacks() + 0x180 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.CompletionCallback(object state) + 0x7a bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ScheduledOverlapped.IOCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* nativeOverlapped) + 0xf bytes
SMDiagnostics.dll!System.ServiceModel.Diagnostics.Utility.IOCompletionThunk.UnhandledExceptionFrame(uint error, uint bytesRead, System.Threading.NativeOverlapped* nativeOverlapped) + 0x3d bytes
mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* pOVERLAP) + 0x54 bytes
[Appdomain Transition]
当它工作时,它有点不同(注意额外的mscorlib条目和中间的转换):
Unflagged > 5408 12 Worker Thread <No Name> CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider Normal
MySecurity.dll!CacheClientCredentialsSecurityTokenManager.CreateSecurityTokenProvider(System.IdentityModel.Selectors.SecurityTokenRequirement tokenRequirement) Line 18
System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.AddSupportingTokenProviders(System.ServiceModel.Security.Tokens.SupportingTokenParameters supportingTokenParameters, bool isOptional, System.Collections.Generic.IList<System.ServiceModel.Security.SupportingTokenProviderSpecification> providerSpecList) + 0xca bytes
System.ServiceModel.dll!System.ServiceModel.Security.SecurityProtocol.OnOpen(System.TimeSpan timeout) + 0xa7 bytes
System.ServiceModel.dll!System.ServiceModel.Security.SymmetricSecurityProtocol.OnOpen(System.TimeSpan timeout) + 0x45 bytes
System.ServiceModel.dll!System.ServiceModel.Security.OperationWithTimeoutAsyncResult.OnScheduled(object state) + 0x82 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke2() + 0x46 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.OnSecurityContextCallback(object o) + 0x28 bytes
***mscorlib.dll!System.Security.SecurityContext.runTryCode(object userData) + 0x6e bytes
[Native to Managed Transition]
[Managed to Native Transition]
***mscorlib.dll!System.Security.SecurityContext.RunInternal(System.Security.SecurityContext securityContext, System.Threading.ContextCallback callBack, object state) + 0xc2 bytes
***mscorlib.dll!System.Security.SecurityContext.Run(System.Security.SecurityContext securityContext, System.Threading.ContextCallback callback, object state) + 0xca bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.WorkItem.Invoke() + 0x4d bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ProcessCallbacks() + 0x180 bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.CompletionCallback(object state) + 0x7a bytes
System.ServiceModel.dll!System.ServiceModel.Channels.IOThreadScheduler.CriticalHelper.ScheduledOverlapped.IOCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* nativeOverlapped) + 0xf bytes
SMDiagnostics.dll!System.ServiceModel.Diagnostics.Utility.IOCompletionThunk.UnhandledExceptionFrame(uint error, uint bytesRead, System.Threading.NativeOverlapped* nativeOverlapped) + 0x3d bytes
mscorlib.dll!System.Threading._IOCompletionCallback.PerformIOCompletionCallback(uint errorCode, uint numBytes, System.Threading.NativeOverlapped* pOVERLAP) + 0x54 bytes
[Appdomain Transition]
答案 0 :(得分:3)
在尝试调用异步方法之前,我没有在代理上显式调用.Open()
,因此.Open()
似乎发生在客户端代理内部,在另一个线程上 - 因此身份问题。我发现如果我打电话:
If _proxy.State <> CommunicationState.Opened Then
_proxy.Open()
End If
_proxy.Begin[asyncMethod]()
缓存凭据设置和令牌缓存检查同步发生,因此使用正确的标识,并按预期运行。