#!/usr/bin/env python # -*- coding: utf-8 -*- # Copyright 2014 Yottabyte import time import hashlib import urllib2 import urllib _access_key = "26d79d9f3e5033d4be8ad5c41355e9be" _secure_key = "10d052f85b421cf4a45ecf287183233d" # @brief: API签名计算 # @param: origin_params 是用户原始的请求hash # @param: secure_key是分发给用户的secure_key # @param: query_time是签名的时间,为以毫秒计的Unix时间戳 # @returns: 长度为32的API签名结果 def _compute_sign(origin_params, secure_key, query_time): sign_arr = [] # 使用签名时间,sk和用户原始请求来生成签名,保证唯一性。 # 注意三个字符串拼接先后顺序是签名时间,原始请求,私钥 sign_arr.append(str(query_time)) sign_arr.append(_sorted_query_str(origin_params)) sign_arr.append(secure_key) return _md5("".join(sign_arr)) # @brief: 通过md5摘要生成算法计算签名 # @param: i_str是待计算的字符串 # @returns: md5的结果截取前32位 def _md5(i_str): h = hashlib.md5() h.update(i_str) return h.hexdigest()[0:32] # @brief: 将用户的原始请求按照key排序后拼接为一个字符串 # @param: query_hash 用户原始的请求参数,可以为空{} # @returns: 原始请求对应的唯一字符串 def _sorted_query_str(query_hash): return "&".join([ k+"="+query_hash[k] for k in sorted(query_hash.keys()) ]) if __name__ == '__main__': #用户的原始请求URI部分 origin_params = {'query': '*'} #统计请求JSON post_body = '{ "query": { "status_split_numberic_histogram_result": { "histogram": { "field": "apache.status", "interval": 100 } }, "method_split_result": { "terms": { "field": "apache.method" }, "group": { "resp_len_stats_result": { "stats": { "field": "apache.resp_len" } } } } } }' #用户请求签名的时间 qtime = int(time.time() * 1000) #计算用户签名 sign = _compute_sign(origin_params, _secure_key, qtime) # 为了验签所有API请求都需要额外增加的参数 additional_params = { 'qt': qtime, 'sign' : sign, 'ak': _access_key, } # 将用户原始参数和额外参数合并 req_params = dict(origin_params.items() + additional_params.items()) # 拼接query req_url = 'http://yottaapi-test:8190/v0/statistic?' + urllib.urlencode(req_params) # 发起请求,获取结果 print(urllib2.urlopen(req_url, data=post_body).read())
java样例:
// Copyright 2014 Yottabyte package cn.yottabyte.api.stats; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import java.security.MessageDigest; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; public class Main { public static String accessKey = "4b40905b8eeee0cab799154c2baef788"; public static String secureKey = "2535c004c17f7565d18ca0bc51df65ac"; // @brief: API签名计算 // @param: originParams 是用户原始的请求hash // @param: secureKey是分发给用户的secure_key // @param: queryTime是签名的时间,为以毫秒计的Unix时间戳 // @return: 长度为32的API签名结果 public static String computeSign(HashMap<String, String> originParams, String secureKey, Long queryTime) { // 使用签名时间,sk和用户原始请求来生成签名,保证唯一性。 // 注意三个字符串拼接先后顺序是签名时间,原始请求,私钥 ArrayList<String> list = new ArrayList<String>(); list.add(queryTime.toString()); list.add(sortedQueryStr(originParams)); list.add(secureKey); return md5(StringUtils.join(list.toArray(new String[0]), "")); } // @brief: 通过md5摘要生成算法计算签名 // @param: sourceStr是待计算的字符串 // @returns: md5的结果截取前32位 public static String md5(String sourceStr) { String result; try { byte[] bytesOfMessage = sourceStr.getBytes("UTF-8"); MessageDigest md = MessageDigest.getInstance("MD5"); byte[] thedigest = md.digest(bytesOfMessage); int i; StringBuffer buf = new StringBuffer(""); for (int offset = 0; offset < thedigest.length; offset++) { i = thedigest[offset]; if (i < 0) i += 256; if (i < 16) buf.append("0"); buf.append(Integer.toHexString(i)); } result = buf.toString(); } catch (Exception e) { System.err.println("Exception in md5."); result = ""; } return result; } // @brief: 将用户的原始请求按照key排序后拼接为一个字符串 // @param: queryHash 用户原始的请求参数,可以为空{} // @returns: 原始请求对应的唯一字符串 public static String sortedQueryStr(HashMap<String, String> queryHash) { String[] keys = queryHash.keySet().toArray(new String[0]); Arrays.sort(keys); ArrayList<String> params = new ArrayList<String>(); for (int i = 0; i < keys.length; i++) { String k = keys[i]; String v = queryHash.get(k); params.add(k + "=" + v); } return StringUtils.join(params.toArray(new String[0]), "&"); } public static void main(String[] args) { HashMap<String, String> originParams = new HashMap<String, String>(); // 用户的原始请求 originParams.put("query", "*"); originParams.put("time_range", "-1h,now"); // 用户请求签名的时间 Long queryTime = new Long(new Date().getTime()); // 计算用户签名 String sign = computeSign(originParams, secureKey, queryTime); // 为了验签所有API请求都需要额外增加的参数 HashMap<String, String> additionalParams = new HashMap<String, String>(); additionalParams.put("qt", queryTime.toString()); additionalParams.put("sign", sign); additionalParams.put("ak", accessKey); // 拼接query URIBuilder uriBuilder = new URIBuilder(); uriBuilder.setScheme("http"); uriBuilder.setHost("yottaapi.test"); uriBuilder.setPort(8190); uriBuilder.setPath("/v0/statistic/"); String[] originKeys = originParams.keySet().toArray(new String[0]); for (int i = 0; i < originKeys.length; i++) { uriBuilder.addParameter(originKeys[i], originParams.get(originKeys[i])); } String[] additionalKeys = additionalParams.keySet().toArray(new String[0]); for (int i = 0; i < additionalKeys.length; i++) { uriBuilder.addParameter(additionalKeys[i], additionalParams.get(additionalKeys[i])); } CloseableHttpClient httpclient = HttpClients.createDefault(); try { // 打印GET方法的uri String uri = uriBuilder.build().toString(); System.out.println(uri); // 发起请求 HttpPost httpPost = new HttpPost(uri); StringEntity stringEntity = new StringEntity( "{ \"query\": { " + " \"status_split_numberic_histogram_result\": { " + "\"histogram\": { " + "\"field\": \"apache.status\"," + "\"interval\": 100 " + "} " + "}," + " \"method_split_result\": { " + "\"terms\": { " + " \"field\": \"apache.method\" " + "}, " + "\"group\": { " + " \"resp_len_stats_result\": { " + "\"stats\": { " + "\"field\": \"apache.resp_len\" " +"} " + "} " +"} " +"} " + " } }"); httpPost.setEntity(stringEntity); CloseableHttpResponse response = httpclient.execute(httpPost); try { System.out.println(response.getStatusLine()); HttpEntity entity = response.getEntity(); // 获得结果 System.out.println(EntityUtils.toString(entity)); EntityUtils.consume(entity); } catch(Exception e) { System.err.println("Handle result exception!" + e.toString()); } finally { response.close(); } } catch(Exception e) { System.err.println("Request Exception!" + e.toString()); } finally { try { httpclient.close(); } catch(Exception e) { System.out.println("Close client Exception!" + e.toString()); } } } }