淘寶台灣開放平台會對每個API請求的身份進行驗證,伺服器也將驗證呼叫參數是否有效。因此,每個 HTTP 請求必須包含簽名資訊,簽名無效的請求將被拒絕。
淘寶台灣開放平台通過 App Key 和分配給應用程式的金鑰來驗證請求的身份。App 金鑰用於在 HTTP 請求 URL 和伺服器端簽名字串時生成簽名字串。請嚴格保密您的金鑰。
如果手動編寫 HTTP 請求(而不使用官方SDK),則需要瞭解以下簽名演算法。
生成簽名的過程如下:
根據ASCII表中的參數名稱對所有請求參數(包括系統和應用程式參數,但“符號”和帶位元組陣列類型的參數除外)進行排序。舉例:
Before sort: foo=1, bar=2, foo_bar=3, foobar=4 After sort: bar=2, foo=1, foo_bar=3, foobar=4
將排序後的參數及其值連接到一個字串中。舉例:bar2foo1foo_bar3foobar4
/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的原始程式碼。