Wif保护了WCF服务,缓存令牌 - 异步wcf方法失去了身份

时间:2011-04-28 01:04:32

标签: wcf caching asynchronous token wif

我有一个使用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]   

1 个答案:

答案 0 :(得分:3)

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

If _proxy.State <> CommunicationState.Opened Then
     _proxy.Open()
End If

_proxy.Begin[asyncMethod]()

缓存凭据设置和令牌缓存检查同步发生,因此使用正确的标识,并按预期运行。