服務(wù)端簽名

2020-02-12 17:17 更新

目標(biāo)

簽名方案只驗(yàn)證 服務(wù)端簽名前的支付數(shù)據(jù) 和 tt.pay 發(fā)送到字節(jié)跳動(dòng)后端的支付數(shù)據(jù) 的一致性(因而,具體字段有哪些,以及字段的值是否正確并不由簽名驗(yàn)證)


生成簽名規(guī)則

Key 篩選

去掉請求參數(shù)中的字節(jié)類型字段(如文件、字節(jié)流)、sign 與 risk_info 字段、value 為空的字段(某些接口請求參數(shù)中特殊標(biāo)明不參與簽名的字段也需要去掉)。

K-V 排序和拼接

把篩選后的 k-v 集合按照 key 的 ASCII 碼升序排序,例如:

a, a1, abc, abcd, abce, abd, b1, ba

k-v 按照 key=value 的格式鏈接,并且按照 key 排序使用 & 連接成一個(gè)字符串,生成待簽名字符串

MD5 加簽

MD5(待簽名字符串 + app_secret); // 待簽名字符串 + app_secret 是字符串直接拼接,待簽名字符串在前,中間沒有連接符。

完整流程

例如下面是我們待驗(yàn)簽的 orderInfo:

{
  app_id: '800000000001',
  merchant_id: '1900000001',
  timestamp: 1570694312,
  sign_type: 'MD5',
  out_order_no: '201900000000000001',
  total_amount: 1,
  product_code: 'pay',
  payment_type: 'direct',
  trade_type: 'H5',
  version: '2.0',
  currency: 'CNY',
  subject: '測試訂單',
  body: '測試訂單',
  uid: '0000000000000001',
  trade_time: 1570585744,
  valid_time: 300,
  notify_url: '',
  risk_info: '{"ip":"120.230.0.0"}',
  wx_type: 'MWEB',
  wx_url: 'https://wx.tenpay.com/xxx',
  alipay_url: 'app_id=2019000000000006&biz_content=xxxx'
}

則待簽名字符串 unsigned_str 為:

alipay_url=app_id=2019000000000006&biz_content=xxxx&app_id=800000000001&body=測試訂單&currency=CNY&merchant_id=1900000001&out_order_no=201900000000000001&payment_type=direct&product_code=pay&sign_type=MD5&subject=測試訂單&timestamp=1570694312&total_amount=1&trade_time=1570585744&trade_type=H5&uid=0000000000000001&valid_time=300&version=2.0&wx_type=MWEB&wx_url=https://wx.tenpay.com/xxx

若你的 app_secret 是 'a',那么帶入上述 unsigned_str,最終 MD5(unsigned_str + app_secret) 后簽名字符串 signed_str 應(yīng)為:

0f1e3358a9898d7c4c6c23740251808a
驗(yàn)證:你可以在你的驗(yàn)簽方法里用上面的 orderInfo 和 app_secret 數(shù)據(jù)測試,驗(yàn)證與我們給出的 unsigned_str 和 signed_str 是否一致保持一致:通過上述方式生成簽名 sign 之后,將該 sign 字段掛在 orderInfo 上并最終透傳至前端 tt.pay,傳遞過程中請不要增刪或修改任何字段(保持服務(wù)端簽名前的支付數(shù)據(jù)和 tt.pay 發(fā)送到字節(jié)跳動(dòng)后端的支付數(shù)據(jù)一致),否則會(huì)導(dǎo)致簽名檢驗(yàn)不通過


簽名代碼示例(以 Node 為例)

const crypto = require("crypto");

const createSign = (params, appSecret) => {
  const paramKeys = Object.keys(params).sort();
  let signStr = "";
  paramKeys.forEach(key => {
    let value = params[key];
    // 空值,risk_info, sign 不參與簽名
    if (!value || ["risk_info", "sign"].indexOf(key) >= 0) {
      return;
    }
    if (signStr.length > 0) {
      signStr += "&";
    }
    if (typeof value === "object") {
      value = JSON.stringify(value);
    }
    signStr += key + "=" + value;
  });
  signStr += `${appSecret}`;
  console.log("signStr:", signStr);
  const md5 = crypto.createHash("md5");
  const sign = md5.update(signStr).digest("hex");
  return sign;
};


簽名驗(yàn)證失敗排查方案

  • 服務(wù)端:服務(wù)端生成簽名方式可能有誤,請參考上方「完整流程」中的 orderInfo 與 app_secret 代入你的簽名方法,驗(yàn)證與我們給出的預(yù)期 unsigned_str 和 signed_str 是否一致,不一致將導(dǎo)致簽名驗(yàn)證失敗
  • 小程序端:請保證帶有 sign 簽名的 orderInfo 由服務(wù)端返回且與 tt.pay 中傳入的 orderInfo 完全一致,不一致將導(dǎo)致簽名驗(yàn)證失敗
  • 反饋:若上面兩者已經(jīng)確認(rèn)無誤,但簽名驗(yàn)證依然無法通過,請?jiān)陂_發(fā)者社區(qū)反饋,反饋中請?zhí)峁┚€上報(bào) CD0025 失敗訂單的 unsigned_str


各語言簽名實(shí)現(xiàn)

可參考以下語言 Demo 中簽名的實(shí)現(xiàn)


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號