【发布时间】: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