このトピックでは、MQTT (Message Queuing Telemetry Transport) プロトコルを使用するデバイスを動的に登録し、DeviceSecretsを取得する方法について説明します。 DeviceSecretsは、デバイスをIoT Platformに接続するときの認証に必要です。 このトピックでは、サンプルJavaコードを事前登録の製品ごとの一意証明書認証に使用します。
前提条件
製品ごとの一意の証明書検証トピックで説明されている次の手順を実行します。
プロダクトを作成します。
動的登録を有効にします。
デバイスを追加します。
デバイスにデバイス証明書をインストールします。
背景情報
IoT Platformは、デバイスの複数の認証方法をサポートしています。 詳細については、「デバイスの認証」をご参照ください。
MQTT接続を確立して、製品ごとの固有証明書の事前登録認証または製品ごとの固有証明書の事前登録認証を実行できます。 MQTTベースの動的登録の手順とパラメーターの詳細については、「MQTTベースの動的登録」をご参照ください。
開発環境の準備
この例では、開発環境は次のコンポーネントで構成されています。
オペレーティングシステム: Windows 10
Java開発キット (JDK): JDK 8
統合開発環境 (IDE): IntelliJ IDEAコミュニティエディション
手順
- IntelliJ IDEAを開き、Mavenプロジェクトを作成します。 この例では、MQTT動的登録プロジェクトが作成されます。
- pom.xmlファイルで、次のMaven依存関係を追加し、[Maven変更の読み込み] をクリックしてパッケージをダウンロードします。
<dependency> <groupId>org.eclipse.paho</groupId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency>
- MQTT動的登録プロジェクトを見つけ、プロジェクトの \src\main \Javaディレクトリにjavaクラスを作成します。 この例では、DynamicRegisterByMqttクラスが作成されます。 次のコードを入力します。 説明
- デバイスがアクティブ化されていない場合は、動的登録を複数回実行できます。 ただし、最新のDeviceSecretのみが有効です。 最新のDeviceSecretがデバイスに書き込まれていることを確認します。
- デバイスがアクティブ化されている場合、ResetThing操作を呼び出して、IoT Platformコンソールでデバイスの登録ステータスを未登録にリセットする必要があります。 次に、デバイスを動的に登録できます。
java.nio.charset.StandardCharsetsをインポートします。java.util.Randomをインポートします。java.util.Setをインポートします。java.util.SortedMapをインポートします。java.util.TreeMapをインポートします。javax.crypto.Macをインポートします。javax.crypto.spec.SecretKeySpecをインポートします。org.eclipse.paho.client.mqttv3.IMqttDeliveryTokenをインポートします。org.eclipse.paho.client.mqttv3.MqttCallbackをインポートします。org.eclipse.paho.client.mqttv3.MqttClientをインポートします。org.eclipse.paho.client.mqttv3.MqttConnectOptionsをインポートします。org.eclipse.paho.client.mqttv3.MqttExceptionをインポートします。org.eclipse.paho.client.mqttv3.MqttMessageをインポートします。org.eclipse.paho.client.mqttv3.persist.MemoryPersistenceをインポートします。com.alibaba.fastjson.JSONObjectをインポートします。/** * デバイスの動的登録を実行します。 * / パブリッククラスDynamicRegisterByMqtt { // 製品が存在するリージョンのID。 プライベート静的文字列regionId = "cn-shanghai"; // 暗号化アルゴリズムを指定します。 有効値: hmacmd5、hmacsha1、および hmacsha256。 指定する値は、signmethodパラメーターの値と同じである必要があります。 プライベート静的最終文字列HMAC_ALGORITHM = "hmacsha1"; // IoT Platformからデバイス証明書を受け取るトピック。 トピックを作成したりサブスクライブしたりすることなく、トピックを直接使用できます。 プライベート静的最終文字列REGISTER_TOPIC = "/ext/register"; /** * ダイナミック登録。 * * @ param productKey: デバイスが属するプロダクトのProductKey。 * @ param productSecret: デバイスが属する製品のProductSecret。 * @ param deviceName: デバイスのDeviceName。 * @throws Exception */ public void register(String productKey, String productSecret, String deviceName) throw Exception { // 認証サービスのエンドポイント。 トランスポート層セキュリティ (TLS) プロトコルを使用する必要があります。 String broker = "ssl://" + productKey + ".iot-as-mqtt" 。+ regionId + ".aliyuncs.com:1883"; // クライアントID。 デバイスのメディアアクセス制御 (MAC) アドレスまたはシリアル番号 (SN) を使用することを推奨します。 クライアントIDの長さは最大64文字です。 String clientId = productKey + "." + deviceName; // ランダムな値を取得します。 ランダムr = new Random(); int random = r.nextInt(1000000); // secureodeパラメーターの値を2に設定します。 値は変更できません。 値2は、TLSが使用されることを指定します。 signmethodパラメータは、暗号化アルゴリズムを指定する。 String clientOpts = "| securemode=2、authType=register、signmethod=" + HMAC_ALGORITHM + "、random=" + random + "|"; // MQTTクライアントのID。 文字列mqttClientId = clientId + clientOpts; // MQTTクライアントのユーザー名。 文字列mqttUsername = deviceName + "&" + productKey; // IoT Platformに接続するためにMQTTクライアントによって使用される署名。 JSONObject params = new JSONObject(); params.put("productKey", productKey); params.put("deviceName", deviceName); params.put("ランダム" 、ランダム); 文字列mqttPassword = sign(params, productSecret); // 動的登録用のMQTT CONNECTメッセージを送信します。 connect(broker、mqttClientId、mqttUsername、mqttPassword); } /** * 動的登録のためにMQTT CONNECTメッセージを送信します。 * * @ param serverURL: 動的登録のエンドポイント。 * @ param clientId: クライアントのID。 * @ param username: MQTTクライアントのユーザー名。 * @ param password: MQTTクライアントのパスワード。 */ @ SuppressWarnings("リソース") private void connect(String serverURL, String clientId, String username, String password) { try { MemoryPersistence persistence = new MemoryPersistence(); MqttClient sampleClient = new MqttClient(serverURL, clientId, persistence); MqttConnectOptions connOpts = new MqttConnectOptions(); connOpts.setMqttVersion(4);// MQTT 3.1.1 connOpts.setUserName(username);// ユーザー名。 connOpts.setPassword(password.toCharArray());// パスワード。 connOpts.setAutomaticReconnect(false); // 動的登録用に構成されているMQTTルールに基づいて、自動再接続機能を無効にします。 System.out.println("----- register params -----"); System.out.print("server=" + serverURL + "、clientId=" + clientId); System.out.println(",username=" + username + ",password=" + password); sampleClient.setCallback(new MqttCallback() { @オーバーライド public void messageArrived(String topic, MqttMessage message) throws Exception { // 動的登録の応答のみを印刷します。 if (REGISTER_TOPIC.equals (トピック)) { String payload = new String(message.getPayload(), StandardCharsets.UTF_8); System.out.println("----- register result -----"); System.out.println (ペイロード); sampleClient.disconnect(); } } @オーバーライド public void deliveryComplete(IMqttDeliveryToken token) { } @オーバーライド public void connectionLost(Throwable cause) { } }); sampleClient.connect(connOpts); } catch (MqttException e) { System.out.print("register failed: clientId=" + clientId); System.out.println(",username=" + username + ",password=" + password); System.out.println("reason" + e.getReasonCode()); System.out.println("msg" + e.getMessage()); System.out.println("loc" + e.getLocalizedMessage()); System.out.println("cause" + e.getCause()); System.out.println("except" e); e.printStackTrace(); } } /** * 動的登録のための署名を生成します。 * * @ param params: 署名の生成に使用できる必須パラメーター。 * @ param productSecret: デバイスが属する製品のProductSecret。 * @ return: 16進形式の署名。 */ プライベート文字列記号 (JSONObject params, String productSecret) { // リクエストパラメータをアルファベット順に並べ替えます。 <String> keys = getSortedKeys(params) を設定します。 // signパラメーターとsignMethodパラメーターを削除します。 キー削除 ("sign"); keys.remove("signMethod"); // 署名のプレーンテキストを取得します。 StringBuffer content = new StringBuffer(); for (String key : keys) { content.append (キー); content.append(params.getString (キー)); } // 署名を生成します。 String sign = encrypt(content.toString(), productSecret); System.out.println("sign content=" + content); System.out.println("sign result=" + sign); リターンサイン; } /** * JSONオブジェクトのキーをアルファベット順に並べ替えます。 * * @ param json: キーをソートするJSONオブジェクト。 * @ return: アルファベット順にソートされたキーのセット。 */ プライベートセット <String> getSortedKeys(JSONObject json) { SortedMap<String, String> map = new TreeMap<String, String>(); for (文字列キー: json.keySet()) { 文字列値=json.getString (キー); map.put (キー、値); } リターンmap.keySet(); } /** * HMAC_ALGORITHMパラメーターを使用して暗号化アルゴリズムを指定します。 * * @ param content: プレーンテキスト。 * @ param secret: 暗号化キー。 * @ return: 暗号文。 */ private String encrypt(String content, String secret) { try { byte[] text = content.getBytes(StandardCharsets.UTF_8); byte[] key = secret.getBytes(StandardCharsets.UTF_8); SecretKeySpec secretKey = new SecretKeySpec(key, HMAC_ALGORITHM); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); byte2hexを返します (mac.doFinal (テキスト)) 。 } catch (Exception e) { e.printStackTrace(); ヌルを返します。 } } /** * バイナリ配列を16進文字列に変換します。 * * @ param b: バイナリ配列。 * @ return: 16進文字列。 */ private String byte2hex(byte[] b) { StringBuffer sb=新しいStringBuffer(); for (int n = 0; b != null && n < b.length; n ++) { String stmp = Integer.toHexString(b[n] & 0XFF); if (stmp.length() == 1) { sb.append('0'); } sb.append(stmp); } sb.toString().toUpperCase(); を返します。 } public static void main(String[] args) throws Exception { 文字列productKey = "a1IoK ******"; 文字列productSecret = "6vEu5Qlj5S ******"; 文字列deviceName = "OvenDevice01"; // 動的登録を実行します。 DynamicRegisterByMqttクライアント=new DynamicRegisterByMqtt(); client.register(productKey, productSecret, deviceName); // 動的登録が成功した場合は、オンプレミスのデバイスにDeviceSecretを書き込みます。 } }
- 以下のパラメーターを指定します。 上記のサンプルコードの値をデバイス情報に置き換えます。
パラメーター 例 説明 regionId cn-shanghai IoT Platformが実行されているリージョンのID。 リージョンIDについては、「リージョン」をご参照ください。 productKey a1IoK ****** デバイスに書き込まれるProductKey。 IoT Platform コンソールにログインし、[Product Details] ページでProductKeyを表示できます。 productSecret 6vEu5Qlj5S ****** デバイスに書き込まれるProductSecret。 IoT Platform コンソールにログインし、[Product Details] ページでProductSecretを表示できます。 deviceName OvenDevice01 デバイスの名前。 IoT Platformは、デバイスがアクティベーション要求を開始するときにDeviceNameを検証します。 デバイスから取得できる識別子をDeviceNameとして使用することを推奨します。 識別子は、デバイスのMACアドレス、International Mobile Equipment Identity (IMEI) 番号、またはSNとすることができる。
ブローカー "ssl://" + productKey ".iot-as-mqtt" + regionId + ".aliyuncs.com:1883" 動的登録で使用されるエンドポイント。 形式: ssl:// "+"${YourInstanceDomain}"+":"+ 1883
${YourInstanceDomain} 変数をMQTTエンドポイントに置き換えます。 MQTTエンドポイントの取得方法については、「インスタンスのエンドポイントの管理」をご参照ください。
- DynamicRegisterByMqtt.javaファイルを実行します。 これにより、デバイスはIoT Platformに認証リクエストを送信できます。 DeviceName、ProductKey、およびProductSecretがリクエストに含まれます。
以下の図に結果を示します。 デバイスが認証に合格した後、デバイスはIoT Platformによって発行されたDeviceSecretを受け取ります。 この例では、DeviceSecretは
8d1f0cdab49dd229cf3b75 *********
です。
次のステップ
デバイスがProductKey、DeviceName、およびDeviceSecretを含むデバイス証明書を取得した後、MQTTクライアントを使用してデバイスをIoT Platformに接続し、データ通信を行うことができます。
詳細については、「Paho MQTT Javaクライアントの使用」をご参照ください。