为什么 WCF 忽略我的 TokenProvider?

Why does WCF ignore my TokenProvider?

我有一个 BizTalk WCF-Custom 接收位置,我在其中添加了自定义行为:

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。

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

The adapter "WCF-Custom" raised an error message. Details "System.UnauthorizedAccessException: 40102: Missing authorization token, Resource: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 ---> System.ServiceModel.FaultException: 40102: Missing authorization token, Resource: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 服务总线终结点会 return 此错误消息的任何原因,除非是因为未使用令牌提供程序。为什么频道会忽略 TokenProvider,我需要做什么才能正确传递令牌?

编辑:

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

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

编辑#2:

我已经反编译了 Microsoft.ServiceBus.dll,我相信我已经找到了实际创建 WCF 消息的 class,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;
    }

所以从逻辑上考虑,缺少授权 header 的原因有两个:

编辑#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 });

这是一个异步方法,return是一个任务。是否会以某种方式阻止此任务的结果在某些情况下不会执行预期的操作,而这会以某种方式弄乱 WCF 通道的配置?正如我所说,我确定此代码 运行s 并分配 TokenProvider。我现在只是不确定什么时候会运行s.

哦!

我没有意识到 Microsoft.ServiceBus.dll 的非常旧版本在与(同样旧的)内部部署版本的服务总线(Windows 的服务总线互操作的解决方案中仍然存在服务器)是我的项目引用的那个。不管出于什么原因,这个版本没有做它应该做的事情,也没有给出任何迹象表明它正在绕过预期的行为。更新到服务总线的当前 NuGet 包解决了这个问题。