签名算法
为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带签名,API网关服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝。API网关目前只支持HAMC_SHA1签名算法,
签名大体过程如下:
①对API中定义的所有输入参数(注意签名字段必须包括API定义中的所有字段,如果某个字段不需要输入参数值,则使用0长度字符串代替参数值,并加入到签名字段列表中),根据参数名称的ASCII码表的顺序排序。如:
foo = 2
bar = 1
foo_bar = 3
foobar = null
排序后的顺序是
bar = 1
foo = 2
foo_bar = 3
foobar = null
②在上述输入参数的前面添加上公共参数中的application和timestamp(使用offset修正后)参数:
application = 10000.1234567
timestamp = 1519637736018
bar = 1
foo = 2
foo_bar = 3
foobar = null
③将排序好的参数名和参数值使用冒号按成对拼接后,再通过换行符将所有键值对连接在一起,根据上面的示例得到的字符串结果为:
application:10000.1234567
timestamp:1519637736018
bar:1
foo:2
foo_bar:3
foobar:
④对于HTTP BODY数据的签名通过二进制的方式追加到最后,参考下面的签名示例代码。
⑤把拼装好的字符串采用utf-8编码,使用签名算法对编码后的字节流进行HMAC_SHA1摘要计算。
⑥将摘要得到的字节流结果再使用Base64进行编码计算得到最后结果:
SeLSjSQezf/z1FqDmuQYsu9B/+g=
具体获取签名以及调用可以参考以下Java代码示例:
/** * @param param api 配置参数表 * @param timestamp UNIX格式时间戳 * @param application appKey,到应用管理打开应用可以找到此值 * @param secret 密钥,到应用管理打开应用可以找到此值 * @param body 请求body数据,如果是GET请求,此值写null * @return 签名数据 */ public static String sign(Map<String, String> param, long timestamp, String application, String secret, byte[] body) throws Exception { // 连接系统参数 StringBuffer sb = new StringBuffer(); sb.append("application").append(":").append(application).append("\n"); sb.append("timestamp").append(":").append(timestamp).append("\n"); // 连接请求参数 if (param != null) { TreeSet<String> keys = new TreeSet<String>(param.keySet()); Iterator<String> i = keys.iterator(); while (i.hasNext()) { String s = i.next(); String val = param.get(s); sb.append(s).append(":").append(val == null ? "" : val).append("\n"); } } //body数据写入需要签名的字符流中 ByteArrayOutputStream baos = new ByteArrayOutputStream(); baos.write(sb.toString().getBytes("utf-8")); if (body != null && body.length > 0) { baos.write(body); baos.write("\n".getBytes("utf-8")); } // 得到需要签名的字符串 String string = baos.toString("utf-8"); System.out.println("Sign string: " + string); // hmac-sha1编码 byte[] bytes = null; SecretKey secretKey = new SecretKeySpec(secret.getBytes("utf-8"), "HmacSha1"); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); bytes = mac.doFinal(string.getBytes("utf-8")); // base64编码 String encryptedString = new String(Base64.encodeBase64(bytes)); // 得到需要提交的signature签名数据 return encryptedString; }