问题描述
在Azure中连接 Service Bus 服务发送消息时发生证书错误,抛出证书异常消息:
或
The X.509 certificate CN=servicebus.chinacloudapi.cn, OU=Azure, O=Shanghai Blue Cloud Technology Co Ltd, L=Shanghai, S=Shanghai, C=CN is not in the trusted people store. The X.509 certificate CN=servicebus.chinacloudapi.cn, OU=Azure, O=Shanghai Blue Cloud Technology Co Ltd, L=Shanghai, S=Shanghai, C=CN chain building failed. The certificate that was used has a trust chain that cannot be verified. Replace the certificate or change the certificateValidationMode. A certificate chain could not be built to a trusted root authority.
问题解答
如果在连接Service Bus的代码中不对 ConnectivityMode 做预先设置,Service Bus SDK默认使用了 AutoDetect 模式 连接 Service Bus 服务。
AutoDetect 会优先使用 TCP 连接模式,由于 TCP 连接模式也是加密的,所以客户端需要首先验证 service bus 服务器证书 CN = servicebus.chinacloudapi.cn 的有效性,证书链信息在 SSL 协议的 server hello 消息中返回。
如果证书链中的某些中间证书没有安装在 web 应用实例上,web 应用需要发起额外的请求到 CA 服务器上下载中间证书并安装。当下面任何一种情况发生时,web 应用无法对 service bus 服务器证书建立信任的证书链,随后会报告上述的证书错误:
- 运行Service Bus客户端代码的实例和 CA 服务器之间存在网络问题,导致无法下载证书.
- 运行Service Bus客户端代码的实例无法成功安装证书,如权限问题等。
推荐在代码中强制使用 HTTPS 模式连接 Service Bus 服务,HTTPS 模式有不同的设计,因此会很大程度上避免上述错误发生。
示例代码如下: string connectionString = "servicebus connection string"; ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Https var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString); if (!namespaceManager.TopicExists("TestTopic")) { namespaceManager.CreateTopic("TestTopic"); } TopicClient client = TopicClient.CreateFromConnectionString(connectionString, "TestTopic"); BrokeredMessage testMessage = new BrokeredMessage("test message"); testMessage.MessageId = "message id"; client.Send(testMessage);
另外,以上代码代码使用很旧的Service Bus SDK,强烈建议升级SDK代码,使用新的AMQP协议连接Service Bus
using Azure.Messaging.ServiceBus; // the client that owns the connection and can be used to create senders and receivers ServiceBusClient client; // The Service Bus client types are safe to cache and use as a singleton for the lifetime // of the application, which is best practice when messages are being published or read // regularly. // // set the transport type to AmqpWebSockets so that the ServiceBusClient uses the port 443. // If you use the default AmqpTcp, you will need to make sure that the ports 5671 and 5672 are open // TODO: Replace the <NAMESPACE-CONNECTION-STRING> and <QUEUE-NAME> placeholders var clientOptions = new ServiceBusClientOptions() { TransportType = ServiceBusTransportType.AmqpWebSockets }; client = new ServiceBusClient("<NAMESPACE-CONNECTION-STRING>", clientOptions);