最初开始接触Azure IoT Hub的时候,被各种connection string和endpoint弄的眼花缭乱。本入门系列旨在将Azure IoT Hub 权限管理机制以及各个接口(endpoint)的用途解释清楚。

首先抛出一个典型的IoT解决方案的架构,以让读者对IoT有个大概的认识。该架构通过平台层的核心服务和应用层组件来实现典型IoT解决方案需要解决的三个主要问题:

  • 设备的连接;
  • 数据的处理、分析与管理;
  • 数据的有效呈现以及业务逻辑的处理。

Azure IoT Hub 入门 - 权限管理

回到本文的主题:IoT Hub 权限管理以及Endpoint。

    1. Azure IoT Hub 权限管理
      总结起来,Azure 提供了以下两种权限管理机制:
      • Hub 层面的共享访问策略(shared access policies)
        在portal上新创建的IoT Hub默认包含了以下策略,你可以对已有的策略进行修改,或者添加新的策略。
        • iothubowner: 拥有所有的权限
        • service: ServiceConnect 权限 (给予服务端通信监控接口访问权限,例如读取device-to-cloud的消息,发送cloud-to-device消息等)
        • device: DeviceConnect 权限(给予设备端的通信接口访问权限,例如发送device-to-cloud消息)
        • registryRead: RegistryRead 权限(读设备注册列表)
        • registryReadWrite: RegistryRead和RegistryWrite权限(读写设备注册列表)  
      • device 层面的安全令牌(security credentials)
        IoT Hub维护了一个所有设备的注册列表。列表里的每一个设备都有自己的symmetric key,用户可以根据这个symmetric key 来获得DeviceConnect的权限。 
      针对特定场景下所需要的权限举例如下:
      * 设备管理组件:registryReadWrite 策略
      * 事物处理组件:service 策略
      * 单设备连接组件:device策略
  1. 如何生成安全令牌
    为避免直接在网络上传输密钥,IoT Hub通过安全令牌来对设备以及云端服务进行授权。一般情况下,Azure IoT Hub SDKs会自动根据密钥生成安全令牌。但在某些情况下(例如直接使用MQTT,AMQP或者HTTP接口)需要客户自己去生成安全令牌。
    安全令牌的格式如下:
    SharedAccessSignature sig={signature-string}&se={expiry}&skn={policyName}&sr={URL-encoded-resourceURI}

    针对每个字段的注解,请参考:https://azure.microsoft.com/en-us/documentation/articles/iot-hub-devguide-security/
    下面给出完整的C#实现:

    public class SharedAccessSignatureBuilder
        {
            private string key;
    
            public string Key
            {
                get
                {
                    return this.key;
                }
                set
                {
                    // StringValidationHelper.EnsureBase64String(value, "Key");
                    this.key = value;
                }
            }
    
            public string KeyName
            {
                get;
                set;
            }
    
            public string Target
            {
                get;
                set;
            }
    
            public TimeSpan TimeToLive
            {
                get;
                set;
            }
    
            public string TargetService
            {
                get;
                set;
            }
    
            public SharedAccessSignatureBuilder()
            {
                this.TimeToLive = TimeSpan.FromMinutes(20);
                TargetService = "iothub";
            }
    
            private static string BuildExpiresOn(TimeSpan timeToLive)
            {
                DateTime dateTime = DateTime.UtcNow.Add(timeToLive);
                TimeSpan timeSpan = dateTime.Subtract(SharedAccessSignatureConstants.EpochTime);
                return Convert.ToString(Convert.ToInt64(timeSpan.TotalSeconds, CultureInfo.InvariantCulture), CultureInfo.InvariantCulture);
            }
    
            private static string BuildSignature(string keyName, string key, string target, TimeSpan timeToLive, string targetService = "iothub")
            {
                string str = SharedAccessSignatureBuilder.BuildExpiresOn(timeToLive);
                string str1 = WebUtility.UrlEncode(target);
                List<string> strs = new List<string>()
                {
                    str1,
                    str
                };
                string str2 = SharedAccessSignatureBuilder.Sign(string.Join("\n", strs), key, targetService);
                StringBuilder stringBuilder = new StringBuilder();
                stringBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0} {1}={2}&{3}={4}&{5}={6}", new object[] { "SharedAccessSignature", "sr", str1, "sig", WebUtility.UrlEncode(str2), "se", WebUtility.UrlEncode(str) });
                if (!string.IsNullOrEmpty(keyName))
                {
                    stringBuilder.AppendFormat(CultureInfo.InvariantCulture, "&{0}={1}", new object[] { "skn", WebUtility.UrlEncode(keyName) });
                }
                return stringBuilder.ToString();
            }
    
            private static string Sign(string requestString, string key, string targetService)
            {
                string base64String;
    
                if (!string.IsNullOrEmpty(targetService) && targetService.ToLower() == "servicebus")
                {
                    using (HMACSHA256 hMACSHA256 = new HMACSHA256(Encoding.UTF8.GetBytes(key))) // key is not decoded
                    {
                        base64String = Convert.ToBase64String(hMACSHA256.ComputeHash(Encoding.UTF8.GetBytes(requestString)));
                    }
                }
                else
                {
                    using (HMACSHA256 hMACSHA256 = new HMACSHA256(Convert.FromBase64String(key))) // key is decoded
                    {
                        base64String = Convert.ToBase64String(hMACSHA256.ComputeHash(Encoding.UTF8.GetBytes(requestString)));
                    }
                }
    
                return base64String;
            }
    
            public string ToSignature()
            {
                return SharedAccessSignatureBuilder.BuildSignature(this.KeyName, this.Key, this.Target, this.TimeToLive, this.TargetService);
            }
        }
    SharedAccessSignatureBuilder

相关文章:

猜你喜欢
相关资源
相似解决方案