淘宝全球开放平台会对每个 API 请求的身份进行验证,伺服器也将验证呼叫参数是否有效。因此,每个 HTTP 请求必须包含签名资讯,签名无效的请求将被拒绝。
淘宝全球开放平台通过 App Key 和分配给应用程式的金钥来验证请求的身份。 App 金钥用于在 HTTP 请求 URL 和伺服器端签名字串时生成签名字串。请严格保密您的金钥。
如果手动编写 HTTP 请求(而不使用官方 SDK),则需要了解以下签名算法。
生成签名的过程如下:
Before sort:
foo=1, bar=2, foo_bar=3, foobar=4
After sort:
bar=2, foo=1, foo_bar=3, foobar=4
将排序后的参数及其值连接到一个字串中。举例:bar2foo1foo_bar3foobar4
在连接的字串前面添加API名称。举例,添加API名称“/test/api”:
/test/apibar2foo1foo_bar3foobar4
hmac_sha256(/test/apibar2foo1foo_bar3foobar4)
hex("helloworld".getBytes("utf-8")) = "68656C6C6F776F726C64"
JAVA 示例代码:
/** * Sign the API request with body. */ public static String signApiRequest(Map<String, String> params, String body, String appSecret, String signMethod, String apiName) throws IOException { // first: sort all text parameters String[] keys = params.keySet().toArray(new String[0]); Arrays.sort(keys); // second: connect all text parameters with key and value StringBuilder query = new StringBuilder(); query.append(apiName); for (String key : keys) { String value = params.get(key); if (areNotEmpty(key, value)) { query.append(key).append(value); } } // third:put the body to the end if (body != null) { query.append(body); } // next : sign the whole request byte[] bytes = null; if(signMethod.equals(Constants.SIGN_METHOD_HMAC)) { bytes = encryptWithHmac(query.toString(), appSecret); } else if(signMethod.equals(Constants.SIGN_METHOD_SHA256)) { bytes = encryptHMACSHA256(query.toString(), appSecret); } // finally : transfer sign result from binary to upper hex string return byte2hex(bytes); } private static byte[] encryptHMACSHA256(String data, String secret) throws IOException { byte[] bytes = null; try { SecretKey secretKey = new SecretKeySpec(secret.getBytes(Constants.CHARSET_UTF8), Constants.SIGN_METHOD_HMAC_SHA256); Mac mac = Mac.getInstance(secretKey.getAlgorithm()); mac.init(secretKey); bytes = mac.doFinal(data.getBytes(Constants.CHARSET_UTF8)); } catch (GeneralSecurityException gse) { throw new IOException(gse.toString()); } return bytes; } /** * Transfer binary array to HEX string. */ public static String byte2hex(byte[] bytes) { StringBuilder sign = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(bytes[i] & 0xFF); if (hex.length() == 1) { sign.append("0"); } sign.append(hex.toUpperCase()); } return sign.toString(); }
C# 示例代码:
public static string SignRequest(IDictionary<string, string> parameters, string body, string appSecret, string signMethod, string apiName) { // first : sort all key with asci order IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters, StringComparer.Ordinal); // second : contact all params with key order StringBuilder query = new StringBuilder(); query.Append(apiName); foreach (KeyValuePair<string, string> kv in sortedParams) { if (!string.IsNullOrEmpty(kv.Key) && !string.IsNullOrEmpty(kv.Value)) { query.Append(kv.Key).Append(kv.Value); } } // third : add body to last if (!string.IsNullOrEmpty(body)) { query.Append(body); } // next : sign the string byte[] bytes = null; if (signMethod.Equals(Constants.SIGN_METHOD_SHA256)) { HMACSHA256 sha256 = new HMACSHA256(Encoding.UTF8.GetBytes(appSecret)); bytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(query.ToString())); } // finally : transfer binary byte to hex string StringBuilder result = new StringBuilder(); for (int i = 0; i < bytes.Length; i++) { result.Append(bytes[i].ToString("X2")); } return result.ToString(); }
PYTHON 示例代码:
def sign(secret,api, parameters): #=========================================================================== # @param secret # @param parameters #=========================================================================== sort_dict = sorted(parameters) parameters_str = "%s%s" % (api, str().join('%s%s' % (key, parameters[key]) for key in sort_dict)) h = hmac.new(secret.encode(encoding="utf-8"), parameters_str.encode(encoding="utf-8"), digestmod=hashlib.sha256) return h.hexdigest().upper()
其他程式设计语言的签名样例代码,请参阅官方 SDK 的原始程式码。