IoT Platform mengautentikasi pengirim setiap permintaan API. Oleh karena itu, Anda harus menyertakan signature dalam semua permintaan API yang menggunakan protokol HTTP atau HTTPS.
Metode signature
Untuk menandatangani permintaan, buka halaman AccessKey Management di Konsol untuk mendapatkan ID AccessKey dan Rahasia AccessKey akun Alibaba Cloud Anda. Selanjutnya, Anda dapat menghasilkan Message Authentication Code (MAC). ID AccessKey mengidentifikasi pengguna, sedangkan Rahasia AccessKey adalah kunci yang digunakan untuk mengenkripsi string signature dan memungkinkan server memverifikasi string tersebut. Pastikan Anda menjaga kerahasiaan Rahasia AccessKey Anda.
IoT Platform menyediakan kit pengembangan perangkat lunak (SDK) sisi server untuk bahasa seperti Java, Python, dan PHP. Penggunaan SDK ini menghilangkan kebutuhan untuk melakukan proses penandatanganan secara manual. Untuk petunjuk penggunaan masing-masing SDK, lihat Server-side SDKs (original) dan Server-side SDKs (upgraded).
Untuk menandatangani permintaan, ikuti langkah-langkah berikut:
Buat string kueri terkanonisasi dari parameter permintaan.
Urutkan parameter.
Urutkan parameter permintaan secara alfabetis berdasarkan nama parameternya. Parameter ini mencakup parameter permintaan umum dan parameter khusus untuk API tersebut. Jangan sertakan parameter Signature itu sendiri.
CatatanSaat Anda menggunakan metode GET untuk mengirim permintaan, parameter-parameter ini merupakan bagian dari URL permintaan yang mengikuti
?dan dipisahkan oleh&.Lakukan URL-encode terhadap nama dan nilai setiap parameter permintaan.
Encode nama dan nilai parameter menggunakan set karakter UTF-8 sesuai aturan dalam RFC 3986. Aturan encoding-nya adalah sebagai berikut:
Karakter A–Z, a–z, 0–9, serta karakter
-,_,., dan~tidak di-encode.Karakter lainnya di-encode dalam format
%XY, di manaXYmerepresentasikan nilai heksadesimal dari kode ASCII karakter tersebut. Sebagai contoh, tanda kutip ganda (") di-encode sebagai%22.Karakter UTF-8 ekstensi di-encode dalam format
%XY%ZA….Spasi harus di-encode sebagai
%20, bukan tanda plus (+).
Metode encoding ini mirip, tetapi tidak identik, dengan algoritma encoding untuk tipe Multipurpose Internet Mail Extensions (MIME)
application/x-www-form-urlencoded.Jika Anda menggunakan
java.net.URLEncoderdari pustaka standar Java, Anda dapat terlebih dahulu meng-encode string menggunakan metodepercentEncode. Kemudian, pada string yang telah di-encode tersebut, ganti tanda plus (+) dengan%20, tanda bintang (*) dengan%2A, dan%7Edengan tilde (~). Hal ini menghasilkan string ter-encode yang sesuai dengan aturan sebelumnya.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; }Gabungkan nama parameter yang telah di-encode dengan nilainya menggunakan tanda sama dengan (=).
Urutkan pasangan parameter-nilai secara alfabetis berdasarkan nama parameternya, lalu gabungkan menggunakan simbol
&.
Setelah menyelesaikan langkah-langkah ini, Anda memperoleh string kueri terkanonisasi.
Buat string yang akan ditandatangani.
Buat string-to-sign dengan memproses string kueri terkanonisasi dari Langkah 1 menggunakan
percentEncode. String tersebut harus dalam format berikut:StringToSign= HTTPMethod + "&" + percentEncode("/") + "&" + percentEncode(CanonicalizedQueryString)Penjelasan parameter:
HTTPMethod: Metode HTTP yang digunakan untuk mengirim permintaan, misalnya GET.
percentEncode("/"): Nilai ter-encode UTF-8 dari garis miring (/), yaitu "%2F".
percentEncode(CanonicalizedQueryString): String kueri terkanonisasi yang telah di-encode persen.
Hitung nilai HMAC.
Gunakan string
StringToSignyang Anda buat di Langkah 2 untuk menghitung nilai HMAC sebagaimana didefinisikan dalam RFC 2104.HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) )PentingKunci untuk perhitungan signature adalah AccessKeySecret Anda diikuti oleh karakter ampersand (
&) (kode ASCII 38). Algoritma hash yang digunakan adalah SHA1.Hitung nilai signature.
Encode nilai HMAC dari Langkah 3 menjadi string menggunakan aturan encoding Base64. String hasilnya adalah nilai signature (Signature).
Signature = Base64( HMAC-SHA1( AccessSecret, UTF-8-Encoding-Of(StringToSign) ) )Tambahkan tanda.
Tambahkan parameter Signature ke parameter permintaan. Nilai parameter ini adalah signature yang dihasilkan, yang harus di-URL-encode sesuai spesifikasi dalam RFC 3986.
Contoh signature
Contoh ini menunjukkan cara memanggil API Pub. Untuk contoh ini, asumsikan nilai parameter berikut: AccessKeyId=testid, AccessKeySecret=testsecret, ProductKey=12345abcde, TopicFullName=/12345abcde/testdevice/user/get, MessageContent=aGVsbG8gd29ybGQ, dan Qos=0.
Buat URL permintaan sebelum ditandatangani.
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/getHitung string yang akan ditandatangani, 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-20Hitung nilai signature.
Karena AccessKeySecret adalah
testsecret, kunci yang digunakan untuk perhitungan adalah testsecret&. Nilai signature yang dihitung adalah:NUh3otvAoXOZmG/a2gDShh6Ze9w=Tambahkan signature ke URL permintaan sebagai parameter Signature. URL akhirnya adalah:
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
Contoh kode Java
Kode Java berikut memberikan contoh cara membuat signature.
Tambahkan dependensi proyek Maven.
<!-- Apache Commons Lang 3.x --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.12.0</version> <!-- Gunakan versi terbaru --> </dependency> <!-- Apache Commons Codec --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-codec</artifactId> <version>1.15</version> <!-- Gunakan versi terbaru --> </dependency>File konfigurasi adalah Config.java.
/* * Copyright 2018 Alibaba. All rights reserved. */ package com.aliyun.iot.demo.sign; /** * File konfigurasi untuk penandatanganan API sisi server * * @author: ali * @version: 0.1 2018-08-08 08:23:54 */ public class Config { // Informasi AccessKey public static String accessKey = "123456******3456"; public static String accessKeySecret = "123456******34567******4567890"; public final static String CHARSET_UTF8 = "utf8"; }Parameter
Contoh
Deskripsi
accessKey
123456******3456
Login ke Konsol IoT Platform. Arahkan pointer ke gambar profil Anda dan klik AccessKey Management untuk mendapatkan ID AccessKey dan Rahasia AccessKey.
CatatanJika Anda menggunakan pengguna Resource Access Management (RAM), Anda harus memberikan izin kepada pengguna RAM tersebut untuk mengelola IoT Platform (AliyunIOTFullAccess). Jika tidak, koneksi akan gagal. Untuk informasi tentang cara memberikan izin, lihat Berikan izin pengguna RAM untuk mengakses IoT Platform.
accessKeySecret
123456******34567******4567890
File konfigurasi adalah 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; /** * Kelas pemrosesan URL * * @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("Kesalahan URL encode:" + 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 { // Setelah di-encode dengan URLEncoder.encode, ganti "+", "*", dan "%7E" agar sesuai dengan spesifikasi encoding API. return value == null ? null : URLEncoder.encode(value, CHARSET_UTF8).replace("+", "%20").replace("*", "%2A").replace("%7E", "~"); } catch (Exception e) { } return ""; } }File konfigurasi adalah 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; /** * Penandatanganan API sisi server * * @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 tidak boleh kosong"); } 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 tidak boleh kosong"); } 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); } }Buat file entri utama 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; /** * Entri utama untuk tool penandatanganan * * @author: ali * @version: 0.1 2018-09-18 15:06:48 */ public class Main { // 1. Ubah informasi AccessKey di Config.java. // 2. Metode 2 direkomendasikan. Semua parameter harus ditentukan. // 3. "Final signature" adalah hasil signature akhir. public static void main(String[] args) throws UnsupportedEncodingException { // Metode 1 System.out.println("Metode 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(); // Metode 2 System.out.println("Metode 2:"); Map<String, String> map = new HashMap<String, String>(); // Parameter umum 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"); // Parameter permintaan 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(); } }