最近更新时间:2022-08-04
以下代码用于演示签名的生成方式、接口调用以及请求结果。本示例中使用测试数据展示,使用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 -> encode(key) + "=" + encode(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 # 生成Url def 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 url if __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" } |