Ejemplo en Java que muestra cómo realizar el registro dinámico con certificado único por producto mediante MQTT para obtener el DeviceSecret necesario en la autenticación de IoT Platform.
Requisitos previos
Complete los siguientes pasos descritos en la documentación de unique-certificate-per-product:
Cree un producto.
Habilite el registro dinámico.
(Solo con prerregistro) Agregue un dispositivo.
Grabe la información del dispositivo en la línea de producción.
Contexto
IoT Platform admite varios métodos de autenticación de dispositivos. Para obtener más información, consulte Device authentication.
IoT Platform permite el registro dinámico mediante MQTT tanto para dispositivos prerregistrados como para aquellos sin prerregistro, a través del método de certificado único por producto. Para conocer los detalles del proceso y los parámetros, consulte Dynamic device registration over MQTT.
Preparación del entorno de desarrollo
Entorno de desarrollo:
Sistema operativo: Windows 10
JDK: JDK 8
Procedimiento
Abra IntelliJ IDEA y cree un proyecto Maven. Para este ejemplo, asigne al proyecto el nombre MqttDynamicRegistration.
-
En el archivo pom.xml del proyecto, agregue las siguientes dependencias de Maven y luego haga clic en el icono Load Maven Changes para descargarlas.
<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> -
En el directorio /src/main/java del proyecto MqttDynamicRegistration, cree una clase Java llamada
DynamicRegisterByMqtty agregue el siguiente código.NotaSi un
dispositivono está activado, puede ejecutar elregistro dinámicovarias veces. ElDeviceSecretde la注册ción más reciente es el que surte efecto. Asegúrese de conservar elDeviceSecretmás reciente en eldispositivo.Si un
dispositivoya está activado, debe llamar a la operación API ResetThing para restablecer su estado deregistro dinámicoa no registrado en la nube antes de poder volver a registrar eldispositivo.
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; /** * Performs dynamic registration for a device. */ public class DynamicRegisterByMqtt { // The region ID where your product is located. private static String regionId = "cn-shanghai"; // The encryption method. The available MAC algorithms are HmacMD5, HmacSHA1, and HmacSHA256. The value must be consistent with the signmethod parameter. private static final String HMAC_ALGORITHM = "hmacsha1"; // The topic for receiving the device certificate from IoT Platform. You can use this topic directly without creating or subscribing to it. private static final String REGISTER_TOPIC = "/ext/register"; /** * Performs dynamic registration. * * @param productKey The ProductKey of the product. * @param productSecret The ProductSecret of the product. * @param deviceName The name of the device. * @throws Exception */ public void register(String productKey, String productSecret, String deviceName) throws Exception { // The endpoint. You must use Transport Layer Security (TLS). String broker = "ssl://" + productKey + ".iot-as-mqtt." + regionId + ".aliyuncs.com:1883"; // The client ID. We recommend that you use the device's MAC address or serial number (SN). The client ID must be within 64 characters. String clientId = productKey + "." + deviceName; // Obtains a random value. Random r = new Random(); int random = r.nextInt(1000000); // The securemode parameter can only be set to 2, which indicates that only TLS can be used. The signmethod parameter specifies the signature algorithm. String clientOpts = "|securemode=2,authType=register,signmethod=" + HMAC_ALGORITHM + ",random=" + random + "|"; // The MQTT client ID for connection. String mqttClientId = clientId + clientOpts; // The MQTT username for connection. String mqttUsername = deviceName + "&" + productKey; // The MQTT password for connection, which is the signature. JSONObject params = new JSONObject(); params.put("productKey", productKey); params.put("deviceName", deviceName); params.put("random", random); String mqttPassword = sign(params, productSecret); // Perform dynamic registration through an MQTT CONNECT message. connect(broker, mqttClientId, mqttUsername, mqttPassword); } /** * Sends dynamic registration information through an MQTT CONNECT message. * * @param serverURL The endpoint for dynamic registration. * @param clientId The client ID. * @param username The MQTT username. * @param password The MQTT password. */ @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); // Use MQTT 3.1.1. connOpts.setUserName(username); // The username. connOpts.setPassword(password.toCharArray()); // The password. connOpts.setAutomaticReconnect(false); // The MQTT dynamic registration protocol requires disabling automatic reconnection. 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 { // Process only the response for dynamic registration. 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(); } } /** * Generates a signature for dynamic registration. * * @param params The parameters used for the signature. * @param productSecret The ProductSecret of the product. * @return The signature as a hexadecimal string. */ private String sign(JSONObject params, String productSecret) { // Sorts the request parameters in alphabetical order. Set<String> keys = getSortedKeys(params); // Excludes the 'sign' and 'signMethod' parameters. keys.remove("sign"); keys.remove("signMethod"); // Assembles the plaintext for the signature. StringBuffer content = new StringBuffer(); for (String key : keys) { content.append(key); content.append(params.getString(key)); } // Calculates the signature. String sign = encrypt(content.toString(), productSecret); System.out.println("sign content=" + content); System.out.println("sign result=" + sign); return sign; } /** * Gets the sorted set of keys from a JSON object. * * @param json The JSON object to sort. * @return The sorted set of keys. */ 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(); } /** * Encrypts content by using the HMAC_ALGORITHM. * * @param content The plaintext. * @param secret The key. * @return The ciphertext. */ 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; } } /** * Converts a byte array to a hexadecimal string. * * @param b The byte array. * @return The hexadecimal string. */ 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"; // Perform dynamic registration. DynamicRegisterByMqtt client = new DynamicRegisterByMqtt(); client.register(productKey, productSecret, deviceName); // After dynamic registration, the DeviceSecret must be persisted locally on the device. } } -
Configure los parámetros del código con la información real de su
dispositivo.Parámetro
Ejemplo
Descripción
regionId
cn-shanghai
El
ID de regiónde suinstanciadeIoT Platform. Para consultar la lista de códigos de región, véase Region list.productKey
a1IoK
La
ProductKeydelproducto, grabada previamente en eldispositivo. Inicie sesión en la consola de IoT Platform y consulte laProductKeyen la página Product Details.productSecret
6vEu5Qlj5S
El
ProductSecretdelproducto, grabado previamente en eldispositivo. Inicie sesión en la consola de IoT Platform y consulte elProductSecreten la página Product Details.deviceName
OvenDevice01
El nombre de su
dispositivo.IoT Platformverifica elDeviceNamedurante la activación deldispositivo. Se recomienda utilizar un identificador que pueda leerse directamente deldispositivo, como su dirección MAC, identidad internacional de equipo móvil (IMEI) o número de serie (SN), comoDeviceName.broker
"ssl://" + productKey + ".iot-as-mqtt." + regionId + ".aliyuncs.com:1883"
El
endpointpara elregistro dinámicodeldispositivo. El formato esssl://" + "${YourInstanceDomain}" + ":" +1883.En este formato, ${YourInstanceDomain} corresponde al
endpointMQTT. Para obtener información sobre cómo conseguir elendpointMQTT, consulte View and configure instance endpoints. -
Ejecute el archivo DynamicRegisterByMqtt.java. El
dispositivoenvía una solicitud de autenticación a la nube que contiene elDeviceName, laProductKeyde suproductoy elProductSecret.Una vez que
IoT Platformverifica la solicitud, eldispositivorecibe elDeviceSecret(por ejemplo,8d1f0cdab49dd229cf3b75****) desde la nube.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
Siguientes pasos
Después de que el dispositivo obtenga el certificado de dispositivo (ProductKey, DeviceName y DeviceSecret), utilice un cliente MQTT para conectarlo a IoT Platform y establecer la comunicación de datos.
Para obtener más información, consulte Paho MQTT Java connection example.