Contoh Java yang menunjukkan cara melakukan unique-certificate-per-product dynamic registration melalui MQTT untuk memperoleh DeviceSecret guna autentikasi pada IoT Platform.
Prasyarat
Anda telah menyelesaikan langkah-langkah berikut yang dijelaskan dalam dokumentasi unique-certificate-per-product:
-
Buat produk.
-
Aktifkan pendaftaran dinamis.
-
(Hanya untuk pra-pendaftaran) Tambahkan perangkat.
-
Unggah informasi perangkat di garis produksi.
Informasi latar belakang
IoT Platform mendukung beberapa metode autentikasi perangkat. Untuk informasi selengkapnya, lihat Device authentication.
IoT Platform mendukung dynamic registration melalui MQTT baik untuk perangkat yang telah dipra-daftarkan maupun perangkat tanpa pendaftaran sebelumnya menggunakan metode unique-certificate-per-product. Untuk detail proses dan parameter, lihat Dynamic device registration over MQTT.
Siapkan lingkungan pengembangan
Lingkungan pengembangan:
-
Sistem operasi: Windows 10
-
JDK: JDK 8
Prosedur
- Buka IntelliJ IDEA dan buat proyek Maven. Untuk contoh ini, beri nama proyek MqttDynamicRegistration.
- Pada file pom.xml proyek, tambahkan dependensi Maven berikut, lalu klik ikon Load Maven Changes untuk mengunduhnya.
<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> - Pada direktori /src/main/java proyek MqttDynamicRegistration, buat kelas Java bernama
DynamicRegisterByMqttdan tambahkan kode berikut.Catatan- Jika suatu
devicebelum diaktifkan, Anda dapat melakukandynamic registrationbeberapa kali.DeviceSecretdari pendaftaran terbaru yang berlaku. PastikanDeviceSecretterbaru dipersistensikan ke dalamdevice. - Jika suatu
devicesudah diaktifkan, Anda harus memanggil operasi API ResetThing untuk mengatur ulang statusdynamic registration-nya menjadi belum terdaftar di cloud sebelum dapat mendaftarkan ulangdevicetersebut.
import java.nio.charset.StandardCharsets; import java.util.Random; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttConnectOptions; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; import com.alibaba.fastjson.JSONObject; /** * Melakukan pendaftaran dinamis untuk perangkat. */ public class DynamicRegisterByMqtt { // ID wilayah tempat produk Anda berada. private static String regionId = "cn-shanghai"; // Metode enkripsi. Algoritma MAC yang tersedia adalah HmacMD5, HmacSHA1, dan HmacSHA256. Nilainya harus konsisten dengan parameter signmethod. private static final String HMAC_ALGORITHM = "hmacsha1"; // Topik untuk menerima sertifikat perangkat dari IoT Platform. Anda dapat langsung menggunakan topik ini tanpa membuat atau berlangganan. private static final String REGISTER_TOPIC = "/ext/register"; /** * Melakukan pendaftaran dinamis. * * @param productKey ProductKey produk. * @param productSecret ProductSecret produk. * @param deviceName Nama perangkat. * @throws Exception */ public void register(String productKey, String productSecret, String deviceName) throws Exception { // Titik akhir. Anda harus menggunakan Transport Layer Security (TLS). String broker = "ssl://" + productKey + ".iot-as-mqtt." + regionId + ".aliyuncs.com:1883"; // ID klien. Disarankan menggunakan alamat MAC atau nomor seri (SN) perangkat. ID klien harus tidak lebih dari 64 karakter. String clientId = productKey + "." + deviceName; // Mendapatkan nilai acak. Random r = new Random(); int random = r.nextInt(1000000); // Parameter securemode hanya dapat diatur ke 2, yang menunjukkan bahwa hanya TLS yang digunakan. Parameter signmethod menentukan algoritma signature. String clientOpts = "|securemode=2,authType=register,signmethod=" + HMAC_ALGORITHM + ",random=" + random + "|"; // ID klien MQTT untuk koneksi. String mqttClientId = clientId + clientOpts; // Username MQTT untuk koneksi. String mqttUsername = deviceName + "&" + productKey; // Password MQTT untuk koneksi, yaitu signature. JSONObject params = new JSONObject(); params.put("productKey", productKey); params.put("deviceName", deviceName); params.put("random", random); String mqttPassword = sign(params, productSecret); // Lakukan pendaftaran dinamis melalui pesan MQTT CONNECT. connect(broker, mqttClientId, mqttUsername, mqttPassword); } /** * Mengirimkan informasi pendaftaran dinamis melalui pesan MQTT CONNECT. * * @param serverURL Titik akhir untuk pendaftaran dinamis. * @param clientId ID klien. * @param username Username MQTT. * @param password Password MQTT. */ @SuppressWarnings("resource") 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); // Gunakan MQTT 3.1.1. connOpts.setUserName(username); // Username. connOpts.setPassword(password.toCharArray()); // Password. connOpts.setAutomaticReconnect(false); // Protokol pendaftaran dinamis MQTT mengharuskan nonaktifkan koneksi ulang otomatis. System.out.println("----- register params -----"); System.out.print("server=" + serverURL + ",clientId=" + clientId); System.out.println(",username=" + username + ",password=" + password); sampleClient.setCallback(new MqttCallback() { @Override public void messageArrived(String topic, MqttMessage message) throws Exception { // Proses hanya respons untuk pendaftaran dinamis. if (REGISTER_TOPIC.equals(topic)) { String payload = new String(message.getPayload(), StandardCharsets.UTF_8); System.out.println("----- register result -----"); System.out.println(payload); sampleClient.disconnect(); } } @Override public void deliveryComplete(IMqttDeliveryToken token) { } @Override 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(); } } /** * Menghasilkan signature untuk pendaftaran dinamis. * * @param params Parameter yang digunakan untuk signature. * @param productSecret ProductSecret produk. * @return Signature dalam bentuk string heksadesimal. */ private String sign(JSONObject params, String productSecret) { // Mengurutkan parameter permintaan secara alfabetis. Set<String> keys = getSortedKeys(params); // Kecualikan parameter 'sign' dan 'signMethod'. keys.remove("sign"); keys.remove("signMethod"); // Menyusun teks biasa untuk signature. StringBuffer content = new StringBuffer(); for (String key : keys) { content.append(key); content.append(params.getString(key)); } // Menghitung signature. String sign = encrypt(content.toString(), productSecret); System.out.println("sign content=" + content); System.out.println("sign result=" + sign); return sign; } /** * Mendapatkan set terurut kunci dari objek JSON. * * @param json Objek JSON yang akan diurutkan. * @return Set terurut kunci. */ private Set<String> getSortedKeys(JSONObject json) { SortedMap<String, String> map = new TreeMap<String, String>(); for (String key : json.keySet()) { String value = json.getString(key); map.put(key, value); } return map.keySet(); } /** * Mengenkripsi konten menggunakan HMAC_ALGORITHM. * * @param content Teks biasa. * @param secret Kunci. * @return Teks terenkripsi. */ 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); return byte2hex(mac.doFinal(text)); } catch (Exception e) { e.printStackTrace(); return null; } } /** * Mengonversi array byte menjadi string heksadesimal. * * @param b Array byte. * @return String heksadesimal. */ private String byte2hex(byte[] b) { StringBuffer sb = new 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); } return sb.toString().toUpperCase(); } public static void main(String[] args) throws Exception { String productKey = "a1IoK******"; String productSecret = "6vEu5Qlj5S******"; String deviceName = "OvenDevice01"; // Lakukan pendaftaran dinamis. DynamicRegisterByMqtt client = new DynamicRegisterByMqtt(); client.register(productKey, productSecret, deviceName); // Setelah pendaftaran dinamis, DeviceSecret harus dipersistensikan secara lokal pada perangkat. } } - Jika suatu
- Konfigurasikan parameter dalam kode dengan informasi
deviceaktual Anda.Parameter Contoh Deskripsi regionId cn-shanghai region IDdariinstansIoT PlatformAnda. Untuk daftar kode wilayah, lihat Region list.productKey a1IoK****** ProductKeydariproduct, yang telah dibakar ke dalamdevice. Anda dapat masuk keIoT Platformconsoledan melihatProductKeypada halaman Product Details.productSecret 6vEu5Qlj5S****** ProductSecretdariproduct, yang telah dibakar ke dalamdevice. Anda dapat masuk keIoT Platformconsoledan melihatProductSecretpada halaman Product Details.deviceName OvenDevice01 Nama deviceAnda.IoT PlatformmemverifikasiDeviceNameselama aktivasidevice. Disarankan menggunakan pengenal yang dapat langsung dibaca daridevice, seperti alamat MAC, International Mobile Equipment Identity (IMEI), atau nomor seri (SN), sebagaiDeviceName.broker "ssl://" + productKey + ".iot-as-mqtt." + regionId + ".aliyuncs.com:1883" endpointuntukdynamic registrationdevice. Formatnya adalahssl://" + "${YourInstanceDomain}" + ":" +1883.Dalam format ini, ${YourInstanceDomain} adalah
endpointMQTT. Untuk informasi cara memperolehendpointMQTT, lihat View and configure instance endpoints. - Jalankan file DynamicRegisterByMqtt.java.
devicemengirimkan permintaan autentikasi ke cloud yang berisiDeviceName,ProductKeydariproduct-nya, danProductSecret.Setelah
IoT Platformmemverifikasi permintaan tersebut,devicemenerimaDeviceSecret(misalnya,8d1f0cdab49dd229cf3b75****) dari cloud.sign content=deviceNameOvenDevice01productKeyaIIoxxxrandom462 sign result=A76A60CEDBA4899D304320A58E8719D75xxx ----- register params ----- server=ssl://aIIoxxx.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883,clientId=aIIoxxx.OvenDevice01|securemode=2,authType=register,signmethod=hmacsha1,random=462335|,username=OvenDevice01&aIIoxxx,password=A76A60CE ----- register result ----- {"deviceSecret":"8d1f0cdab49dd229cf3b75xxx","productKey":"aIIoxxx","deviceName":"OvenDevice01"} Process finished with exit code 0
Langkah selanjutnya
Setelah device memperoleh device certificate (ProductKey, DeviceName, dan DeviceSecret), gunakan klien MQTT untuk menghubungkannya ke IoT Platform guna komunikasi data.
Untuk informasi selengkapnya, lihat Paho MQTT Java connection example.