Todos los productos
Search
Centro de documentos

IoT Platform:Mecanismo de firma

Última actualización: Sep 08, 2026

IoT Platform autentica al remitente de cada solicitud de API. Por lo tanto, debe incluir una firma en todas las solicitudes de API que usen el protocolo HTTP o HTTPS.

Método de firma

Para firmar una solicitud, vaya a la AccessKey Management en la consola para obtener el AccessKey ID y el AccessKey secret de su cuenta de Alibaba Cloud. Después, genere un código de autenticación de mensajes (MAC). El AccessKey ID identifica al usuario. El AccessKey secret es la clave que se usa para cifrar la cadena de firma y para que el servidor compruebe dicha cadena. Mantenga su AccessKey secret en estricta confidencialidad.

Nota

IoT Platform proporciona kits de desarrollo de software (SDK) del lado del servidor para lenguajes como Java, Python y PHP. Al usar estos SDK, no necesita ejecutar el proceso de firma de forma manual. Para conocer las instrucciones de uso de cada SDK, consulte Server-side SDKs (original) y Server-side SDKs (upgraded).

Siga estos pasos para firmar la solicitud:

  1. Construya una cadena de consulta canónica a partir de los parámetros de la solicitud.

    1. Ordene los parámetros.

      Ordene los parámetros de la solicitud alfabéticamente por nombre de parámetro. Estos parámetros incluyen common request parameters y los parámetros personalizados de la API. No incluya el propio parámetro Signature.

      Nota

      Cuando use el método GET para enviar una solicitud, estos parámetros corresponden a la parte de la URL de la solicitud que va después de ? y están separados por &.

    2. Codifique con URL el nombre y el valor de cada parámetro de la solicitud.

      Codifique los nombres y valores de los parámetros con el juego de caracteres UTF-8 según las reglas de RFC 3986. Las reglas de codificación son las siguientes:

      • Los caracteres de la A a la Z, de la a a la z, del 0 al 9 y los caracteres -, _, . y ~ no se codifican.

      • Los demás caracteres se codifican con el formato %XY, donde XY representa el valor hexadecimal del código ASCII del carácter. Por ejemplo, las comillas dobles (") se codifican como %22.

      • Los caracteres UTF-8 extendidos se codifican con el formato %XY%ZA….

      • El espacio se debe codificar como %20 y no como signo más (+).

      Este método de codificación es similar al algoritmo del tipo Multipurpose Internet Mail Extensions (MIME) application/x-www-form-urlencoded, pero no es idéntico.

      Si usa java.net.URLEncoder de la biblioteca estándar de Java, primero codifique la cadena con el método percentEncode. Luego, en la cadena codificada, reemplace el signo más (+) por %20, el asterisco (*) por %2A y %7E por una tilde (~). Así obtendrá una cadena codificada que cumple con las reglas anteriores.

      private static final String ENCODING = "UTF-8";
      private static String percentEncode(String value) throws UnsupportedEncodingException {
      return value != null ? URLEncoder.encode(value, ENCODING).replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
      }
    3. Una el nombre del parámetro codificado y su valor con un signo igual (=).

    4. Ordene los pares de parámetro y valor alfabéticamente por nombre de parámetro y concaténelos con el símbolo &.

    Al completar estos pasos, obtendrá la cadena de consulta canónica.

  2. Construya la cadena que se va a firmar.

    Cree la cadena para firmar al procesar la cadena de consulta canónica del paso 1 con percentEncode. La cadena debe tener el siguiente formato:

    StringToSign=
      HTTPMethod + "&" +                      
      percentEncode("/") + "&" +              
      percentEncode(CanonicalizedQueryString)

    Descripción de los parámetros:

    • HTTPMethod: el método HTTP que se usa para enviar la solicitud, como GET.

    • percentEncode("/"): el valor codificado en UTF-8 de la barra diagonal (/), que es "%2F".

    • percentEncode(CanonicalizedQueryString): la cadena de consulta canónica codificada con porcentaje.

  3. Calcule el valor HMAC.

    Use la cadena StringToSign que creó en el paso 2 para calcular el valor HMAC según se define en RFC 2104.

    HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) )
    Importante

    La clave para el cálculo de la firma es su AccessKeySecret seguido de un carácter de Y comercial (&, código ASCII 38). El algoritmo de hash es SHA1.

  4. Calcule el valor de la firma.

    Codifique el valor HMAC del paso 3 en una cadena mediante las reglas de codificación Base64. La cadena resultante es el valor de la firma (Signature).

    Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) )
  5. Agregue la firma.

    Agregue el parámetro Signature a los parámetros de la solicitud. El valor de este parámetro es la firma resultante, la cual se debe codificar con URL según se especifica en RFC 3986.

Ejemplo de firma

En este ejemplo se muestra cómo llamar a la API Pub. Para este ejemplo, asuma los siguientes valores de parámetro: AccessKeyId=testid, AccessKeySecret=testsecret, ProductKey=12345abcde, TopicFullName=/12345abcde/testdevice/user/get, MessageContent=aGVsbG8gd29ybGQ y Qos=0.

  1. Construya la URL de la solicitud antes de firmarla.

    http://iot.cn-shanghai.aliyuncs.com/?Action=Pub&MessageContent=aGVsbG8gd29ybGQ&Timestamp=2018-07-31T07:43:57Z&SignatureVersion=1.0&Format=XML&Qos=0&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2018-01-20&AccessKeyId=testid&SignatureMethod=HMAC-SHA1&RegionId=cn-shanghai&ProductKey=12345abcde&TopicFullName=/12345abcde/testdevice/user/get
  2. Calcule la cadena que se va a firmar, StringToSign.

    GET&%2F&AccessKeyId%3Dtestid%26Action%3DPub%26Format%3DXML%26MessageContent%3DaGVsbG8gd29ybGQ%26ProductKey%3D12345abcde%26Qos%3D0%26RegionId%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf%26SignatureVersion%3D1.0%26Timestamp%3D2018-07-31T07%253A43%253A57Z%26TopicFullName%3D%252F12345abcde%252Ftestdevice%252Fuser%252Fget%26Version%3D2018-01-20
  3. Calcule el valor de la firma.

    Dado que AccessKeySecret es testsecret, la clave que se usa para el cálculo es testsecret&. El valor de la firma calculada es:

    NUh3otvAoXOZmG/a2gDShh6Ze9w=
  4. Agregue la firma a la URL de la solicitud como el parámetro Signature. La URL final es:

    http://iot.cn-shanghai.aliyuncs.com/?MessageContent=aGVsbG8gd29ybGQ&Action=Pub&Timestamp=2018-07-31T07%253A43%253A57Z&SignatureVersion=1.0&Format=XML&Qos=0&SignatureNonce=3ee8c1b8-83d3-44af-a94f-4e0ad82fd6cf&Version=2018-01-20&AccessKeyId=testid&Signature=NUh3otvAoXOZmG%2Fa2gDShh6Ze9w%3D&SignatureMethod=HMAC-SHA1&RegionId=cn-shanghai&ProductKey=12345abcde&TopicFullName=%2F12345abcde%2Ftestdevice%2Fuser%2Fget

Ejemplo de código Java

A continuación se muestra un ejemplo de código Java para crear una firma.

  1. Agregue las dependencias del proyecto Maven.

    <!-- Apache Commons Lang 3.x -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version> <!-- Use the latest version -->
    </dependency>
    
    <!-- Apache Commons Codec -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.15</version> <!-- Use the latest version -->
    </dependency>
  2. El archivo de configuración es Config.java.

    /*   
     * Copyright  2018 Alibaba. All rights reserved.
     */
    package com.aliyun.iot.demo.sign;
    
    /**
     * Configuration file for server-side API signing
     * 
     * @author: ali
     * @version: 0.1 2018-08-08 08:23:54
     */
    public class Config {
    
        // AccessKey information
        public static String accessKey = "123456******3456";
        public static String accessKeySecret = "123456******34567******4567890";
    
        public final static String CHARSET_UTF8 = "utf8";
    }

    Parámetro

    Ejemplo

    Descripción

    accessKey

    1234563456

    Inicie sesión en la consola de IoT Platform. Pase el puntero sobre su foto de perfil y haga clic en AccessKey Management para obtener el AccessKey ID y el AccessKey secret.

    Nota

    Si usa un usuario de Resource Access Management (RAM), debe otorgarle permisos para gestionar IoT Platform (AliyunIOTFullAccess). De lo contrario, la conexión fallará. Para obtener información sobre cómo otorgar permisos, consulte Grant a RAM user permissions to access IoT Platform.

    accessKeySecret

    123456345674567890

  3. El archivo de configuración es UrlUtil.java.

    /*   
     * Copyright  2018 Alibaba. All rights reserved.
     */
    package com.aliyun.iot.demo.sign;
    
    import java.net.URLEncoder;
    import java.util.Map;
    
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * URL processing class
     * 
     * @author: ali
     * @version: 0.1 2018-06-21 20:40:52
     */
    public class UrlUtil {
    
        private final static String CHARSET_UTF8 = "utf8";
    
        public static String urlEncode(String url) {
            if (!StringUtils.isEmpty(url)) {
                try {
                    url = URLEncoder.encode(url, "UTF-8");
                } catch (Exception e) {
                    System.out.println("URL encode error:" + e.getMessage());
                }
            }
            return url;
        }
    
        public static String generateQueryString(Map<String, String> params, boolean isEncodeKV) {
            StringBuilder canonicalizedQueryString = new StringBuilder();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                if (isEncodeKV)
                    canonicalizedQueryString.append(percentEncode(entry.getKey())).append("=")
                            .append(percentEncode(entry.getValue())).append("&");
                else
                    canonicalizedQueryString.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
            if (canonicalizedQueryString.length() > 1) {
                canonicalizedQueryString.setLength(canonicalizedQueryString.length() - 1);
            }
            return canonicalizedQueryString.toString();
        }
    
        public static String percentEncode(String value) {
            try {
                // After encoding with URLEncoder.encode, replace "+", "*", and "%7E" to meet the API encoding specifications.
                return value == null ? null
                        : URLEncoder.encode(value, CHARSET_UTF8).replace("+", "%20").replace("*", "%2A").replace("%7E",
                                "~");
            } catch (Exception e) {
    
            }
            return "";
        }
    }
  4. El archivo de configuración es SignatureUtils.java.

    /*   
     * Copyright  2018 Alibaba. All rights reserved.
     */
    package com.aliyun.iot.demo.sign;
    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.net.URLDecoder;
    import java.net.URLEncoder;
    import java.util.Map;
    import java.util.TreeMap;
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    
    import org.apache.commons.codec.binary.Base64;
    import org.apache.commons.lang3.StringUtils;
    
    /**
     * Server-side API signing
     * 
     * @author: ali
     * @version: 0.1 2018-06-21 20:47:05
     */
    public class SignatureUtils {
    
        private final static String CHARSET_UTF8 = "utf8";
        private final static String ALGORITHM = "HmacSHA1";
        private final static String SEPARATOR = "&";
    
        public static Map<String, String> splitQueryString(String url)
                throws URISyntaxException, UnsupportedEncodingException {
            URI uri = new URI(url);
            String query = uri.getQuery();
            final String[] pairs = query.split("&");
            TreeMap<String, String> queryMap = new TreeMap<String, String>();
            for (String pair : pairs) {
                final int idx = pair.indexOf("=");
                final String key = idx > 0 ? pair.substring(0, idx) : pair;
                if (!queryMap.containsKey(key)) {
                    queryMap.put(key, URLDecoder.decode(pair.substring(idx + 1), CHARSET_UTF8));
                }
            }
            return queryMap;
        }
    
        public static String generate(String method, Map<String, String> parameter, String accessKeySecret)
                throws Exception {
            String signString = generateSignString(method, parameter);
            System.out.println("signString---" + signString);
            byte[] signBytes = hmacSHA1Signature(accessKeySecret + "&", signString);
            String signature = newStringByBase64(signBytes);
            System.out.println("signature----" + signature);
            if ("POST".equals(method))
                return signature;
            return URLEncoder.encode(signature, "UTF-8");
        }
    
        public static String generateSignString(String httpMethod, Map<String, String> parameter) throws IOException {
            TreeMap<String, String> sortParameter = new TreeMap<String, String>();
            sortParameter.putAll(parameter);
            String canonicalizedQueryString = UrlUtil.generateQueryString(sortParameter, true);
            if (null == httpMethod) {
                throw new RuntimeException("httpMethod can not be empty");
            }
            StringBuilder stringToSign = new StringBuilder();
            stringToSign.append(httpMethod).append(SEPARATOR);
            stringToSign.append(percentEncode("/")).append(SEPARATOR);
            stringToSign.append(percentEncode(canonicalizedQueryString));
            return stringToSign.toString();
        }
    
        public static String percentEncode(String value) {
            try {
                return value == null ? null
                        : URLEncoder.encode(value, CHARSET_UTF8).replace("+", "%20").replace("*", "%2A").replace("%7E",
                                "~");
            } catch (Exception e) {
            }
            return "";
        }
    
        public static byte[] hmacSHA1Signature(String secret, String baseString) throws Exception {
            if (StringUtils.isEmpty(secret)) {
                throw new IOException("secret can not be empty");
            }
            if (StringUtils.isEmpty(baseString)) {
                return null;
            }
            Mac mac = Mac.getInstance("HmacSHA1");
            SecretKeySpec keySpec = new SecretKeySpec(secret.getBytes(CHARSET_UTF8), ALGORITHM);
            mac.init(keySpec);
            return mac.doFinal(baseString.getBytes(CHARSET_UTF8));
        }
    
        public static String newStringByBase64(byte[] bytes) throws UnsupportedEncodingException {
            if (bytes == null || bytes.length == 0) {
                return null;
            }
            return new String(Base64.encodeBase64(bytes, false), CHARSET_UTF8);
        }
    }
  5. Cree el archivo de entrada principal Main.java.

    /*   
     * Copyright  2018 Alibaba. All rights reserved.
     */
    package com.aliyun.iot.demo.sign;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Main entry for the signing tool
     * 
     * @author: ali
     * @version: 0.1 2018-09-18 15:06:48
     */
    public class Main {
    
        // 1. Modify the AccessKey information in Config.java.
        // 2. Method 2 is recommended. All parameters must be specified.
        // 3. "Final signature" is the final signature result.
        public static void main(String[] args) throws UnsupportedEncodingException {
    
            // Method 1
            System.out.println("Method 1:");
            String str = "GET&%2F&AccessKeyId%3D" + Config.accessKey
                    + "%26Action%3DRegisterDevice%26DeviceName%3D1533023037%26Format%3DJSON%26ProductKey%3DaxxxUtgaRLB%26RegionId%3Dcn-shanghai%26SignatureMethod%3DHMAC-SHA1%26SignatureNonce%3D1533023037%26SignatureVersion%3D1.0%26Timestamp%3D2018-07-31T07%253A43%253A57Z%26Version%3D2018-01-20";
            byte[] signBytes;
            try {
                signBytes = SignatureUtils.hmacSHA1Signature(Config.accessKeySecret + "&", str.toString());
                String signature = SignatureUtils.newStringByBase64(signBytes);
                System.out.println("signString---" + str);
                System.out.println("signature----" + signature);
                System.out.println("Final signature: " + URLEncoder.encode(signature, Config.CHARSET_UTF8));
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println();
    
            // Method 2
            System.out.println("Method 2:");
            Map<String, String> map = new HashMap<String, String>();
            // Common parameters
            map.put("Format", "JSON");
            map.put("Version", "2018-01-20");
            map.put("AccessKeyId", Config.accessKey);
            map.put("SignatureMethod", "HMAC-SHA1");
            map.put("Timestamp", "2018-07-31T07:43:57Z");
            map.put("SignatureVersion", "1.0");
            map.put("SignatureNonce", "1533023037");
            map.put("RegionId", "cn-shanghai");
            // Request parameters
            map.put("Action", "RegisterDevice");
            map.put("DeviceName", "1533023037");
            map.put("ProductKey", "axxxUtgaRLB");
            try {
                String signature = SignatureUtils.generate("GET", map, Config.accessKeySecret);
                System.out.println("Final signature: " + signature);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println();
        }
    }