日志易restful api提供对日志易系统的调用接口。当前仅作为日志易企业版的一部分发布,便于用户以灵活的方式集成日志易系统。
访问日志易restful api服务需要进行签名验证。签名验证的目的是:
通过给用户分发access_key、secure_key,api服务提供了基于md5的签名验证机制。其中针对重复请求攻击,api服务承诺会接受当前时间一分钟之内的请求,对于签名生成时间到api服务接收时间之间间隔超过一分钟的请求则直接拒绝。
请从api服务提供者处获取一对access_key和secure_key。key的形式为长度为32的字符串。举例如下:
签名计算过程:
=
进行字符串链接,每对key之间用&
进行字符串链接,构造一个用来生成签名的字符串sorted_query_str在原始请求之上,添加 { ‘qt’: query_time, ‘ak’: access_key, ‘sign’: sign } 作为额外参数即可使用签名访问api服务。
下面的python样例程序演示了如何使用签名:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 凯发备用 copyright 2014 yottabyte
import time
import hashlib
import urllib2
import urllib
_access_key = "535479d978359bf4975acf7e7f3f0147"
_secure_key = "e31429454b845ae95ece2cbeae06a3a6"
# @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__':
#用户的原始请求
origin_params = {'query': '*'}
#用户请求签名的时间
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/search/timeline/?' urllib.urlencode(req_params)
# 发起请求,获取结果
print(urllib2.urlopen(req_url).read())
java版:
// 凯发备用 copyright 2014 yottabyte
package cn.yottabyte.api;
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.utils.uribuilder;
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 = "319fcdc428de7204eb2df6a0a0c95a76";
public static string securekey = "9cbca466e9621976d52013f4eb375356";
// @brief: api签名计算
// @param: originparams 是用户原始的请求hash
// @param: securekey是分发给用户的secure_key
// @param: querytime是签名的时间,为以毫秒计的unix时间戳
// @return: 长度为32的api签名结果
public static string computesign(hashmap originparams,
string securekey,
long querytime) {
// 使用签名时间,sk和用户原始请求来生成签名,保证唯一性。
// 注意三个字符串拼接先后顺序是签名时间,原始请求,私钥
arraylist list = new arraylist();
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 queryhash) {
string[] keys = queryhash.keyset().toarray(new string[0]);
arrays.sort(keys);
arraylist params = new arraylist();
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 originparams = new hashmap();
// 用户的原始请求
originparams.put("query", "*");
// 用户请求签名的时间
long querytime = new long(new date().gettime());
// 计算用户签名
string sign = computesign(originparams, securekey, querytime);
// 为了验签所有api请求都需要额外增加的参数
hashmap additionalparams = new hashmap();
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/search/timeline/");
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);
// 发起请求
httpget httpget = new httpget(uri);
closeablehttpresponse response = httpclient.execute(httpget);
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());
}
}
}
}