Wif安全WCF服务,缓存令牌-异步WCF方法失去身份



我有一个使用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 AUTHORITYNETWORK SERVICE"作为身份。结果,对STS的调用具有错误的凭据,并且身份验证失败。(STS日志显示一条消息,指示"无法验证"。

我一直在尝试在Begin/End异步方法周围添加显式模拟,但这并不总是有效。然后,我在web.config中添加了以下值:

    <legacyImpersonationPolicy enabled="false" />
    <alwaysFlowImpersonationPolicy enabled="true" />

这也不总是有效(尽管有时有效)。这里不寻常的事情是,业务逻辑涉及3次尝试调用异步方法(如果调用失败)。我发现通常前2个失败,而第三个成功-即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]   

在尝试调用异步方法之前,我没有在代理上显式地调用.Open(),因此.Open()似乎发生在客户端代理内部,在另一个线程上-因此存在身份问题。我发现如果我调用:

If _proxy.State <> CommunicationState.Opened Then
     _proxy.Open()
End If
_proxy.Begin[asyncMethod]()

缓存的凭据设置和令牌缓存检查同步进行,因此使用正确的标识和预期的功能。

最新更新