使用 SAS 令牌通过 IoT Hub 发送 C2D 消息时的 InvalidErrorCode

InvalidErrorCode when sending C2D message through IoT Hub with SAS token

我想将云到设备消息 (C2D) 发送到 IoTHub 中已知的设备。我在代码中使用 SERVICE 策略。发送发生在控制台应用程序(目前)或稍后的 WebApi 中。所以代码不会运行在设备上!

我想使用 SAS 令牌连接过期,而不是连接设备的对称密钥。我创建了以下代码:

辅助类:

..
using Microsoft.Azure.Devices;
using Microsoft.Azure.Devices.Common.Security;
..

public static class ServiceClientSasConnectionHelper
{
    public static string GetSasConnectionString(SasTokenModel sasTokenModel)
    {
        var sasToken = GetSasToken(sasTokenModel);
        var connectionString = string.Empty;
        if (!string.IsNullOrEmpty(sasTokenModel.PolicyName))
            connectionString = IotHubConnectionStringBuilder.Create(sasTokenModel.HostName, AuthenticationMethodFactory.CreateAuthenticationWithSharedAccessPolicyToken(sasTokenModel.PolicyName, sasToken)).ToString();
        else
            connectionString = $"HostName={sasTokenModel.HostName};DeviceId={sasTokenModel.DeviceId};SharedAccessSignature={sasToken}";
        return connectionString;
    }

    private static string GetSasToken(SasTokenModel sasTokenModel)
    {
        var sasBuilder = new SharedAccessSignatureBuilder
        {
            Key = sasTokenModel.SigninKey,
            Target = $"{sasTokenModel.HostName}/devices/{sasTokenModel.DeviceId}",
            TimeToLive = TimeSpan.FromMinutes(sasTokenModel.TokenLifeTimeInMinutes)
        };

        var sasToken = sasBuilder.ToSignature();

        if (!string.IsNullOrEmpty(sasTokenModel.PolicyName))
            sasToken += $"&skn={sasTokenModel.PolicyName}";

        return sasToken;
    }
}

调用自PROGRAM.CS:

var policyName = string.Empty;
policyName = ConfigHelper.GetPolicyName();  //service
var hostName = ConfigHelper.GetIotUri(); //companyname-Tenant2Display.azure-devices.net
var policyKey = ConfigHelper.GetPolicyKey(); // primarary key from Portal

var sasTokenModel = new SasTokenModel
{
    DeviceId = WebUtility.UrlEncode(deviceKeyPair.Id), //DeviceId
    SigninKey = string.IsNullOrEmpty(policyName) ? deviceKeyPair.Key : policyKey,
    HostName = hostName,
    PolicyName = policyName,
    TokenLifeTimeInMinutes = 5
};
var connString = ServiceClientSasConnectionHelper.GetSasConnectionString(sasTokenModel);
var serviceClient = ServiceClient.CreateFromConnectionString(connString);
await serviceClient.SendAsync(deviceId, commandMessage);

调用 SendAsync 时收到错误消息:

\r\nTracking Id:fee6f860bdff42faa7cad8f81095223e-G:10-TimeStamp:04/19/2017 21:09:32

在属性代码处异常,值为:Microsoft.Azure.Devices.Common.Exceptions.ErrorCode.InvalidErrorCode

堆栈跟踪:

at Microsoft.Azure.Devices.AmqpServiceClient.d__28.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at TelemetrySender.Service.Sender.d__1.MoveNext() in C:\repo\TelemetrySender.cs:line 34

我查看了 de service 部分中的 Github 存储库 "azure-iot-sdk-csharp",但找不到此错误的原因。 我确实看到了设置错误消息的位置,但我不明白为什么。

谁能帮帮我?

I want to send a cloud to device message (C2D) to a device... I want to use a SAS-token to connect with expiration, instead of connecting with the symmetric key of the device

您无法使用设备级凭据发送云到设备消息。您需要使用 IoT 中心级凭据。

因此,您需要删除 GetSasToken()Target 中的 /devices/{sasTokenModel.DeviceId}。最后的SAS-token will have this format:

SharedAccessSignature sig={signature-string}&se={expiry}&skn={policyName}&sr={URL-encoded-resourceURI}

我无法重现您的问题。我在桌面上测试 OS 版本是 10.0.14393.

但我可以使用您的不完整代码和正确的 SAS 令牌格式成功发送云到设备消息(前面提到过)。你可以参考一下。