最近更新时间:2022-02-24
以下代码用于演示签名的生成方式、接口调用以及请求结果。本示例中使用测试数据展示,使用QueryCamera接口作为样例接口。在实际对接过程中,请注意使用对应环境的地址,并替换相关接口的参数信息。
import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.google.common.base.Joiner;import org.apache.http.HttpEntity;import org.apache.http.client.config.RequestConfig;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClientBuilder;import org.apache.http.util.EntityUtils;import sun.misc.BASE64Encoder;import javax.crypto.Mac;import javax.crypto.SecretKey;import javax.crypto.spec.SecretKeySpec;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import java.util.SimpleTimeZone;import java.util.stream.Collectors;public class SignatureUtil { private final static String ISO8601_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; // 紫光云账号下创建的AccessKey Id private static final String accessKeyId = "请根据实际填写"; // 紫光云账号下创建的AccessKey Secret private static final String accessKeySecret = "请根据实际填写"; // 请求方式根据实际填写 private static final String method = "GET"; // 以QueryCamera接口为例,其他接口请替换对应接口名称及接口参数 public static void main(String[] args) throws Exception { // 请求参数 // 包含 公共参数 和 接口参数 JSONObject params = new JSONObject(); // 以下为公共参数(除Signature) // 返回类型 params.put("Format", "json"); // 接口版本号 params.put("Version", "2021-10-15"); params.put("AccessKeyId", accessKeyId); // 签名方法 params.put("SignatureMethod", "HMAC-SHA1"); // 请求发起时间 params.put("Timestamp", generateTimestamp()); // 签名版本号 params.put("SignatureVersion", "1.0"); // 签名随机字符串 params.put("SignatureNonce", "6a6e0ca6-4557-11e5-86a2-b8e8563dc8d2"); // 接口对应参数 // 需要调用的接口名称,这里以查询摄像头信息为例 params.put("Action", "QueryCamera"); // 紫光云openapi服务接入地址 // 生成http请求url String url = endpoint + getUrl(params) + getSignature(params, accessKeySecret); System.out.println("请求地址 : " + url); // 发送GET请求 String result = senRequest(url); JSONObject resultObject = JSON.parseObject(result); System.out.printf("请求结果 : " + resultObject); } // GET请求参数拼接转换 public static String getUrl(JSONObject json) { List<String> urlParamList = json.keySet().stream().map(key -> key + "=" + json.getString(key)).collect(Collectors.toList()); String url = Joiner.on("&").join(urlParamList); return url; } // 签名生成 public static String getSignature(JSONObject json, String accessKeySecret) throws Exception { // 使用UTF-8字符集对参数进行URL编码,同时处理参数中的特殊字符 List<String> paramList = json.keySet().stream().map(key -> encode(key) + "=" + encode(json.getString(key))).collect(Collectors.toList()); // 排序参数 List<String> pList = paramList.stream().map(SignatureUtil::encode).sorted().collect(Collectors.toList()); // 规范化请求参数 String canonicalizedQueryString = Joiner.on("%26").join(pList); System.out.println("规范化参数 : " + canonicalizedQueryString); // 生成 stringToSign String stringToSign = Joiner.on("&").join(method, URLEncoder.encode("/", "utf-8"), canonicalizedQueryString); System.out.println("stringToSign : " + stringToSign); // 生成 hmac String hmac = encode(HmacSHA1Encrypt(stringToSign, accessKeySecret + "&")); System.out.println("签名 : " + hmac); // 返回签名 return "&Signature=" + hmac; } // 加密 public static String HmacSHA1Encrypt(String encryptText, String encryptKey) throws Exception { //根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称 SecretKey secretKey = new SecretKeySpec(encryptKey.getBytes(), "HmacSHA1"); //生成一个指定 Mac 算法 的 Mac 对象 Mac mac = Mac.getInstance("HmacSHA1"); //用给定密钥初始化 Mac 对象 mac.init(secretKey); //完成 Mac 操作 byte[] rawHmac = mac.doFinal(encryptText.getBytes()); return new BASE64Encoder().encode(rawHmac); } // 使用UTF-8进行URL编码,并处理特殊字符 public static String encode(String s) { try { return s != null ? URLEncoder.encode(s, "UTF-8").replace("+", "%20") .replace("*", "%2A").replace("%7E", "~") : null; } catch (UnsupportedEncodingException e) { e.printStackTrace(); return ""; } } // 生成时间戳(标准时间) public static String generateTimestamp() { Date date = new Date(System.currentTimeMillis()); SimpleDateFormat df = new SimpleDateFormat(ISO8601_DATE_FORMAT); df.setTimeZone(new SimpleTimeZone(0, "GMT")); return df.format(date); } // 发送请求 public static String senRequest(String url) throws Exception { RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(3000).build(); CloseableHttpClient httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build(); HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = httpClient.execute(httpGet); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != 200) { httpGet.abort(); throw new RuntimeException("HttpClient,error status code :" + statusCode); } HttpEntity entity = response.getEntity(); String result = null; if (entity != null) { result = EntityUtils.toString(entity, "utf-8"); EntityUtils.consume(entity); response.close(); return result; } else { return null; } }} |
# UTF-8 编码并处理特殊字符def percent_encode(s): encoding = sys.stdin.encoding if sys.stdin.encoding is not None else 'UTF-8' res = urllib.parse.quote(s.encode('utf8').decode(encoding)) res = res.replace('+', '%20') res = res.replace('*', '%2A') res = res.replace('%7E', '~') return res# 生成签名def compute_signature(parameters, accesskey_secret): sorted_parameters = sorted(parameters.items(), key=lambda parameters: parameters[0]) canonicalized_query_string = '' for (k, v) in sorted_parameters: canonicalized_query_string += '&' + percent_encode(k) + '=' + percent_encode(v) string_to_sign = 'GET&%2F&' + percent_encode(canonicalized_query_string[1:]) print("##util 生成签名前字符串(signString): %s" % string_to_sign) h = hmac.new((accesskey_secret + "&").encode('utf-8'), string_to_sign.encode('utf-8'), sha1) signature = base64.encodebytes(h.digest()).strip() return signature# 生成Urldef compose_url(parameters, accesskey_secret, cdn_server_address): signature = compute_signature(parameters, accesskey_secret) print("##util 生成签名结果:%s" % signature) parameters['Signature'] = signature url = cdn_server_address + "?" + urllib.parse.urlencode(parameters) print("##util 拼接url结果: %s" % url) return urlif __name__ == '__main__': # 紫光云账号下创建的AccessKey Id ak = '请根据实际填写' # 紫光云账号下创建的AccessKey Secret sk = '请根据实际填写' # 以QueryCamera接口为例,其他接口请替换对应接口名称及接口参数 user_params = { # 以下为公共参数 # 返回类型 'Format': 'JSON', # 接口版本号 'Version': '2021-10-15', 'AccessKeyId': ak, # 签名方法 'SignatureMethod': 'HMAC-SHA1', # 请求发起时间 'Timestamp': time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), # 签名版本号 'SignatureVersion': '1.0', # 签名随机字符串 'SignatureNonce': '6a6e0ca6-4557-11e5-86a2-b8e8563dc8d2', # 接口对应参数 # 需要调用的接口名称,这里以查询摄像头信息为例 'Action': 'QueryCamera' } # 服务接入地址 # 紫光云openapi服务接入地址 https://api.unicloud.com/univms print("请求地址 : %s" % url) res = requests.get(url) print("请求结果 : %s" % res.text) |
返回结果默认为JSON格式,样例如下:
{ "Code": "0", "Data": { "PageNum": 1, "CameraList": [{ "GroupId": "uni03411202109f70ec205", "Name": "0001", "UpdateTime": "2021-08-13T07:59:12Z", "GroupName": "wjw-02", "DeviceId": "f9e4137ac09f4b319b4f961532989c87", "StreamStatus": "off", "Type": "ipc", "DeviceStatus": "unregistered", "ChannelId": "0", "ManageStatus": "stop", "GbDeviceId": "01234567891312323233", "ParentId": "f9e4137ac09f4b319b4f961532989c87", "CreateTime": "2021-08-13T07:59:12Z", "ParentName": "0001" }], "PageSize": 20, "TotalCount": 14, "PageTotal": 1 }, "RequestId": "601a692f-659e-44eb-b496-2c8decb64dcd"} |