AWS IOT通过https获取Shadow的签名过程
背景:由于公司之前的项目获取iot shadow的时候是通过mqtt获取,需要先订阅才能获得数据,实时性并不高,研究了一下aws的官方文档发现还可以通过https的途径获取shadow信息,但是前提是需要对url进行签名,签名的过程比较繁琐,而且官方文档提供的信息太少,所以这里提供一下通过iam认证签名过程的源码,供大家参考。
以下提供python版和java签名过程的代码
python版本
import hashlib, hmac
import requests
import datetime
import json
def sign(key, msg):
signstr = hmac.new(key, msg.encode("utf-8"), hashlib.sha256).digest()
return signstr
def getSignatureKey(key, dateStamp, regionName, serviceName):
kDate = sign(('AWS4' + key).encode("utf-8"), dateStamp)
kRegion = sign(kDate, regionName)
kService = sign(kRegion, serviceName)
kSigning = sign(kService, ('aws4_request'))
return kSigning
def getResquestUri():
#这里填你的accessKey,需要在aws后台开一个管理员权限的iam用户,然后拿到key和secret
AccessKeyId = "*********";
#这里填你的secretKey
SecretAccessKey = "*******“;
method = 'GET'
#TestDevices我给Ting起的名称这里换成你自己
canonical_uri = "/things/TestDevice/shadow"
protocol = 'https'
service = 'iotdevicegateway'
host = 'a2uwfjmcba1ne3-ats.iot.ap-northeast-1.amazonaws.com'
region = 'ap-northeast-1'
algorithm = 'AWS4-HMAC-SHA256'
date_time = str(datetime.datetime.utcnow().strftime("%Y%m%dT%H%M%SZ"))
date = date_time[0:8]
# credentials = sts_mqtt(clientid, device_list)['Credentials']
credentialScope = date + '/' + region + '/' + service + '/' + 'aws4_request'
canonicalQuerystring = 'X-Amz-Algorithm=' + algorithm
canonicalQuerystring += '&X-Amz-Credential=' + (AccessKeyId + '/' + credentialScope).replace("/",
"%2F")
canonicalQuerystring += '&X-Amz-Date=' + date_time
canonicalQuerystring += '&X-Amz-Expires=3600'
canonicalQuerystring += '&X-Amz-SignedHeaders=host'
canonical_headers = 'host:' + host + '\n'
payload_hash = hashlib.sha256('').hexdigest()
canonical_request = method + '\n' + canonical_uri + '\n' + canonicalQuerystring + '\n' + canonical_headers + '\nhost\n' + payload_hash
signing_key = getSignatureKey(SecretAccessKey, date, region, service)
string_to_sign = algorithm + '\n' + date_time + '\n' + credentialScope + '\n' + hashlib.sha256(
canonical_request).hexdigest()
signature = hmac.new(signing_key, (string_to_sign).encode("utf-8"), hashlib.sha256).hexdigest()
canonicalQuerystring += '&X-Amz-Signature=' + signature
# canonicalQuerystring += '&X-Amz-Security-Token=' + quote(credentials['SessionToken'])
requestUrl = protocol + '://' + host + canonical_uri + '?' + canonicalQuerystring
return requestUrl
r = requests.get(getResquestUri())
print(getResquestUri())
print(r.json())
java版本
public String getRequestUrl(){
String requestUrl = "";
try {
String method = "GET";
//TestDevices我给Ting起的名称这里换成你自己
String canonical_uri = "/things/TestDevice/shadow";
String protocol = "https";
String service = "iotdevicegateway";
String host = "a2uwfjmcba1ne3-ats.iot.ap-northeast-1.amazonaws.com";
String region = "ap-northeast-1";
String algorithm = "AWS4-HMAC-SHA256";
//这里填你的accessKey,需要在aws后台开一个管理员权限的iam用户,然后拿到key和secret
String access_key = "********";
//这里填你的secretKey
String secret_key = "********";
TimeZone timeZone = TimeZone.getTimeZone("UTC");
// Create a date for headers and the credential string
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
simpleDateFormat.setTimeZone(timeZone);
String date_time = simpleDateFormat.format(new Date());
SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyyMMdd");
simpleDateFormat2.setTimeZone(timeZone);
String date = simpleDateFormat2.format(new Date());
// credentials = sts_mqtt(clientid, device_list)["Credentials"]
String credentialScope = date + "/" + region + "/" + service + "/" + "aws4_request";
String canonicalQuerystring = "X-Amz-Algorithm=" + algorithm;
canonicalQuerystring += "&X-Amz-Credential=" + (access_key + "/" + credentialScope).replace("/", "%2F");
canonicalQuerystring += "&X-Amz-Date=" + date_time;
canonicalQuerystring += "&X-Amz-Expires=3600";
canonicalQuerystring += "&X-Amz-SignedHeaders=host";
String canonical_headers = "host:" + host + "\n";
String payload_hash = getSHA256("");
String canonical_request = method + "\n" + canonical_uri + "\n" + canonicalQuerystring + "\n" + canonical_headers + "\nhost\n" + payload_hash;
byte[] signing_key = getSignatureKey(secret_key, date, region, service);
String string_to_sign = algorithm + "\n" + date_time + "\n" + credentialScope + "\n" + getSHA256(canonical_request);
String signature = byte2Hex(HmacSHA256(string_to_sign, signing_key));
canonicalQuerystring += "&X-Amz-Signature=" + signature;
requestUrl = protocol + "://" + host + canonical_uri + "?" + canonicalQuerystring;
}catch (Exception e){
e.printStackTrace();
}
return requestUrl;
}
/**
* * 利用java原生的类实现SHA256加密
* * @param str 加密后的报文
* * @return
*/
public static String getSHA256(String str) {
MessageDigest messageDigest;
String encodestr = "";
try {
messageDigest = MessageDigest.getInstance("SHA-256");
messageDigest.update(str.getBytes("UTF-8"));
encodestr = byte2Hex(messageDigest.digest());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return encodestr;
}
/**
* * 将byte转为16进制
* * @param bytes
* * @return
*/
private static String byte2Hex(byte[] bytes) {
StringBuffer stringBuffer = new StringBuffer();
String temp = null;
for (int i = 0; i < bytes.length; i++) {
temp = Integer.toHexString(bytes[i] & 0xFF);
if (temp.length() == 1) {
//1得到一位的进行补0操作
stringBuffer.append("0");
}
stringBuffer.append(temp);
}
return stringBuffer.toString();
}
static byte[] HmacSHA256(String data, byte[] key) throws Exception {
String algorithm = "HmacSHA256";
Mac mac = Mac.getInstance(algorithm);
mac.init(new SecretKeySpec(key, algorithm));
return mac.doFinal(data.getBytes("UTF-8"));
}
static byte[] getSignatureKey(String key, String dateStamp, String regionName, String serviceName) throws Exception {
byte[] kSecret = ("AWS4" + key).getBytes("UTF-8");
byte[] kDate = HmacSHA256(dateStamp, kSecret);
byte[] kRegion = HmacSHA256(regionName, kDate);
byte[] kService = HmacSHA256(serviceName, kRegion);
byte[] kSigning = HmacSHA256("aws4_request", kService);
return kSigning;
}
有疑问请联系邮箱 569133338@qq.com