【问题标题】:Why does WCF ignore my TokenProvider?为什么 WCF 会忽略我的 TokenProvider?
【发布时间】:2017-04-16 00:57:10
【问题描述】:

我有一个已添加自定义行为的 BizTalk WCF 自定义接收位置:

public class SasTokenProviderEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
    {
        public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
        {
                var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(sharedAccessSecretName, sharedAccessKey);
                bindingParameters.Add(new TransportClientEndpointBehavior { TokenProvider = tokenProvider });         
        }
    }
}

为简洁省略了参数设置代码

这改编自https://code.msdn.microsoft.com/How-to-integrate-BizTalk-07fada58#content 上的一个示例 - 该作者在 BizTalk 社区中广受尊重,并且此类代码已使用多年。我所做的只是调整他使用的方法,这种方法被证明是有效的,以替换不同的 TokenProvider。

我可以通过调试看到这段代码运行了,并且将带有正确参数的 TransportClientEndpointBehavior 添加到了通道中。但是,当 BizTalk 接收位置轮询服务总线时,我在事件日志中看到以下内容:

适配器“WCF-Custom”引发了错误消息。详细信息“System.UnauthorizedAccessException:40102:缺少授权令牌,资源:sb://[namespace].servicebus.windows.net/[queue]。TrackingId:452c2534-d3e6-400f-874f-09be324e9e11_G27,SystemTracker:[namespace]。 servicebus.windows.net:[queue],时间戳:12/1/2016 11:38:56 AM ---> System.ServiceModel.FaultException:40102:缺少授权令牌,资源:sb://[namespace].servicebus .windows.net/[queue].TrackingId:452c2534-d3e6-400f-874f-09be324e9e11_G27, SystemTracker:[namespace].servicebus.windows.net:[queue], Timestamp:12/1/2016 11:38:56 AM

我看不出 Azure 服务总线端点会返回此错误消息的任何原因,除非是因为未使用令牌提供程序。为什么频道会忽略 TokenProvider,我该怎么做才能正确传递令牌?

编辑:

我已经检查了相关端口的原始 WCF 消息流量以及使用 SB-Messaging 适配器的端口,它按预期工作。不同之处在于 SB-Messaging 适配器的消息包含一个 SOAP 标头,如:

<Authorization xmlns="http://schemas.microsoft.com/servicebus/2010/08/protocol/">SharedAccessSignature sr=[really long encoded string]</Authorization> 和我的自定义绑定端口的消息没有。所以问题确实是缺少授权 SOAP 标头;但问题仍然存在 - 为什么频道不添加此标头?

编辑#2:

我已经反编译了 Microsoft.ServiceBus.dll,并且我相信我已经找到了实际创建 WCF 消息的类 Microsoft.ServiceBus.Messaging.Sbmp.SbmpMessageCreator。它有这个方法:

private Message CreateWcfMessageInternal(string action, object body, bool includeToken, string parentLinkId, RetryPolicy policy, TrackingContext trackingContext, RequestInfo requestInfo)
    {
      Message message = Message.CreateMessage(this.messageVersion, action, body);
      MessageHeaders headers = message.Headers;
      headers.To = this.logicalAddress;
      string sufficientClaims = this.GetSufficientClaims();
      if (this.linkInfo != null)
      {
        if (!string.IsNullOrEmpty(this.linkInfo.TransferDestinationEntityAddress))
        {
          SecurityToken authorizationToken = this.GetAuthorizationToken(this.linkInfo.TransferDestinationEntityAddress, sufficientClaims);
          if (authorizationToken != null)
          {
            SimpleWebSecurityToken webSecurityToken = (SimpleWebSecurityToken) authorizationToken;
            if (webSecurityToken != null)
              this.linkInfo.TransferDestinationAuthorizationToken = webSecurityToken.Token;
          }
        }
        this.linkInfo.AddTo(headers);
      }
      if (includeToken)
      {
        ServiceBusAuthorizationHeader authorizationHeader = this.GetAuthorizationHeader(sufficientClaims);
        if (authorizationHeader != null)
          headers.Add((MessageHeader) authorizationHeader);
      }
      if (this.messagingFactory.FaultInjectionInfo != null)
        this.messagingFactory.FaultInjectionInfo.AddToHeader(message);
      if (!string.IsNullOrWhiteSpace(parentLinkId))
        message.Properties["ParentLinkId"] = (object) parentLinkId;
      if (trackingContext != null)
        TrackingIdHeader.TryAddOrUpdate(headers, trackingContext.TrackingId);
      MessageExtensionMethods.AddHeaderIfNotNull<RequestInfo>(message, "RequestInfo", "http://schemas.microsoft.com/netservices/2011/06/servicebus", requestInfo);
      return message;
    }

所以从逻辑上考虑,缺少 Authorization 标头有两个原因:

  • includeToken 是假的(为什么会这样?)
  • GetAuthorizationHeader() 返回 null(为什么?)

编辑#3:

我已经编译并运行了示例代码,并且可以正常工作。我的代码和他的唯一显着区别是我的代码包含调用 Azure Key Vault 的行:

var kv = new KeyVaultClient(this.GetAccessToken);
var key = kv.GetSecretAsync(this.KeyVaultUri.AbsoluteUri, this.SharedAccessSecretName).Result;
var sharedAccessKey = key.Value;
var tokenProvider = TokenProvider.CreateSharedAccessSignatureTokenProvider(
            this.SharedAccessSecretName, 
            sharedAccessKey);
bindingParameters.Add(new TransportClientEndpointBehavior { TokenProvider = tokenProvider });

这是一个返回任务的异步方法。在某些情况下,是否会以某种方式阻止此任务的结果并不能达到预期的效果,并且这会以某种方式扰乱 WCF 通道的配置?正如我所说,我确信这段代码运行并分配了 TokenProvider。我现在只是不确定什么时候它运行。

【问题讨论】:

  • 您是否尝试通过将 Visual Studio 附加到运行端口的主机实例进行调试?
  • @Dijkgraaf 是的,这就是我可以向自己证明 TokenProvider 被分配到它应该在的位置的方式。我唯一想到的另一个想法是,在正常的服务总线场景中,可能有一个特殊的通道工厂会做一些“事情”来完成这项工作,而 BizTalk 可能会有一个沼泽标准 ChannelFactory 或一个 BizTalk-具体的一个,他们都不知道那个特殊的逻辑。我现在无法进行调查,但我会在某个时候跟进这种可能性。
  • 我正在通过一个应该证明先前断言的示例进行工作 - 我越来越相信情况确实如此。 this example 建议为了让服务总线场景在 WCF 中工作,必须调用 CustomBinding.BuildChannelFactory;这将委托给传输绑定元素以实际创建通道。在单元测试中调用它会返回一个 ServiceBusChannelFactory - WCF 适配器 这样做。我相信这就是 Paolo 的SessionChannelBindingElement 很重要的原因。

标签: wcf biztalk azureservicebus azure-servicebus-queues


【解决方案1】:

D'OH!

我没有意识到,我们仍然在与(同样旧的)本地版本的服务总线(Windows Server 的服务总线)互操作的解决方案中使用了非常旧的 Microsoft.ServiceBus.dll 版本是引用的版本通过我的项目。无论出于何种原因,这个版本只是没有做它应该做的事情,并且没有给出任何迹象表明它正在绕过预期的行为。更新以使用服务总线的当前 NuGet 包可解决问题。

【讨论】:

  • 我对你的勇气和愿意回来回答的意愿投了赞成票。这结束了我们脑海中可能挥之不去的问题的循环。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-04
  • 1970-01-01
相关资源
最近更新 更多