签名

UseePay 使用签名-验签名机制来防止数据传输的过程中被篡改。目前 API 集成 UseePay 支持两种签名方式: MD5, RSA。无论是 MD5 还是 RSA 方式, sign 和 value trim后为空的 key-value 都不参与签名计算过程!

MD5

生成MD5密钥

在 UseePay 商户后台的配置中心->密钥管理中点击获取MD5密钥

生成MD5签名规则

  1. 按照ASCII码生序对请求的 payload 进行排序

  2. 按第一步获取的结果,进行key-value 遍历, 对 value trim 后不为空的 key-value 使用 URL 键值对的格式进行拼接(key1=value1&key2=value2...),

  3. 第2步取到字符串, 拼接上 &pkey=商户的MD5密钥, 然后对该字符串进行MD5, 得到的值即为签名值

MD5签名生成示例

function getPayload(){
    payload['version'] = '1.0'
    payload['autoRedirect'] = false
    payload['transactionId'] = ORDER_ID_IN_YOUR_SYSTEM
    payload['transactionType'] = 'pay'
    payload['transactionExpirationTime'] = 14400
    payload['appId'] = YOUR_APP_ID
    payload['amount'] = 1234
    payload['currency'] = 'USD'
    
    const userInfo = {
        userId: USER_ID_IN_YOUR_SYSTEM,
        phoneNo: USER'S_PHONE_NO,
        email: USER'S_EMAIL,
        IP: USER'S_IP
    }
    payload['userInfo'] = JSON.stringify(userInfo)
    
    const payerInfo = {
        paymentMethod: 'credit_card',
        authorizationMethod: 'cvv'
    }
    const billingAddress = {}
    billingAddress['houseNo'] = CUSTOMER'S_HOUSE_NO
    billingAddress['email'] = CUSTOMER'S_EMAIL
    billingAddress['phoneNo'] = CUSTOMER'S_PHONE_NO
    billingAddress['firstName'] = CUSTOMER'S_FIRST_NAME
    billingAddress['lastName'] = CUSTOMER'S_LAST_NAME
    billingAddress['street'] = CUSTOMER'S_STREET
    billingAddress['postalCode'] = CUSTOMER'S_POSTAL_CODE
    billingAddress['city'] = CUSTOMER'S_CITY
    billingAddress['state'] = CUSTOMER'S_STATE
    billingAddress['country'] = CUSTOMER'S_COUNTRY // ISO 3166-1-alpha-2
    payerInfo['billingAddress'] = billingAddress
    payload['payerInfo'] = JSON.stringify(payerInfo)
    
    const orderInfo = {
        subject: ORDER_SUBJECT_IN_YOUR_SYSTEM,
    }
    const goodsInfo = Array()
    goodsInfo.push(
      {
        id: SKU_ID_IN_YOUR_SYSTEM,
        name: PRODUCT_NAME,
        price: PRICE,
        quantity: QUANTITY,
        url: PRODUCT_LINK,
        image: IMAGE_OF_PRODUCT
      },
      {    
        id: SKU_ID_IN_YOUR_SYSTEM,
        name: PRODUCT_NAME,
        price: PRICE,
        quantity: QUANTITY,
        url: PRODUCT_LINK,
        image: IMAGE_OF_PRODUCT
      },
    )
    const shippingAddress = {}
    shippingAddress['houseNo'] = CUSTOMER'S_HOUSE_NO
    shippingAddress['email'] = CUSTOMER'S_EMAIL
    shippingAddress['phoneNo'] = CUSTOMER'S_PHONE_NO
    shippingAddress['firstName'] = CUSTOMER'S_FIRST_NAME
    shippingAddress['lastName'] = CUSTOMER'S_LAST_NAME
    shippingAddress['street'] = CUSTOMER'S_STREET
    shippingAddress['postalCode'] = CUSTOMER'S_POSTAL_CODE
    shippingAddress['city'] = CUSTOMER'S_CITY
    shippingAddress['state'] = CUSTOMER'S_STATE
    shippingAddress['country'] = CUSTOMER'S_COUNTRY // ISO 3166-1-alpha-2
    orderInfo['goodsInfo'] = goodsInfo
    orderInfo['shippingAddress'] = shippingAddress
    payload['orderInfo'] = JSON.stringify(orderInfo)
    
    payload['signType'] = 'MD5'
    payload['merchantNo'] = YOUR_MERCHANT_NO
    payload['notifyUrl'] = ASYNC_NOTIFY_URL
    payload['echoParam'] = ECHO_PARAM
    payload['sign'] = calcMD5(payload)

}

function calcMD5(payload) {
  const data = Object.keys(payload)
    .sort()
    .reduce((obj, key) => {
      obj[key] = payload[key]
      return obj
    }, {})
  var str = ''
  Object.keys(data).forEach((key) => {
    if (data[key] != '' && key != 'sign') {
      str = str + key + '=' + data[key] + '&'
    }
  })
  str = str + 'pkey=' + YOUR_MD5_SECRET_KEY
  return md5(str)
}

RSA

生成商户RSA密钥对

注意: RSA的格式为 1024 PKCS8

访问如 http://www.metools.info/code/c80.html 生成密钥对:

上传商户RSA公钥

注意, 请将公钥字符串中的首行(-----BEGIN PUBLIC KEY-----)与尾行(------END PUBLICK KEY-----)删除, 然后将中间部分格式化成一行粘贴进去

保存 UseePay RSA 公钥

在上图中, 你需要保存 UseePay RSA 公钥, 请求的响应数据, UseePay 会使用 UseePay 的 RSA 私钥进行签名, 并返回 sign 值, 你需要使用 UseePay RSA 公钥进行验签

生成RSA签名规则

  1. 按照ASCII码生序对请求的 payload 进行排序

  2. 按第一步获取的结果,进行key-value 遍历, 对 value trim 后不为空和 key 不为 sign 的 key-value 使用 URL 键值对的格式进行拼接(key1=value1&key2=value2...),

  3. 对第2步取到字符串, 用之前生成的商户 RSA 密钥进行签名做 base64, 获取 sign 值

RSA签名生成示例

// Node.js 示例倒入了 node-rsa
const NodeRSA = require('node-rsa')

function getPayload(){
    payload['version'] = '1.0'
    payload['autoRedirect'] = false
    payload['transactionId'] = ORDER_ID_IN_YOUR_SYSTEM
    payload['transactionType'] = 'pay'
    payload['transactionExpirationTime'] = 14400
    payload['appId'] = YOUR_APP_ID
    payload['amount'] = 1234
    payload['currency'] = 'USD'
    
    const userInfo = {
        userId: USER_ID_IN_YOUR_SYSTEM,
        phoneNo: USER'S_PHONE_NO,
        email: USER'S_EMAIL,
        IP: USER'S_IP
    }
    const billingAddress = {}
    billingAddress['houseNo'] = CUSTOMER'S_HOUSE_NO
    billingAddress['email'] = CUSTOMER'S_EMAIL
    billingAddress['phoneNo'] = CUSTOMER'S_PHONE_NO
    billingAddress['firstName'] = CUSTOMER'S_FIRST_NAME
    billingAddress['lastName'] = CUSTOMER'S_LAST_NAME
    billingAddress['street'] = CUSTOMER'S_STREET
    billingAddress['postalCode'] = CUSTOMER'S_POSTAL_CODE
    billingAddress['city'] = CUSTOMER'S_CITY
    billingAddress['state'] = CUSTOMER'S_STATE
    billingAddress['country'] = CUSTOMER'S_COUNTRY // ISO 3166-1-alpha-2
    payerInfo['billingAddress'] = billingAddress
    payload['userInfo'] = JSON.stringify(userInfo)
    
    const payerInfo = {
        paymentMethod: 'credit_card',
        authorizationMethod: 'cvv'
    }
    payload['payerInfo'] = JSON.stringify(payerInfo)
    
    const orderInfo = {
        subject: ORDER_SUBJECT_IN_YOUR_SYSTEM,
    }
    const goodsInfo = Array()
    goodsInfo.push(
      {
        id: SKU_ID_IN_YOUR_SYSTEM,
        name: PRODUCT_NAME,
        price: PRICE,
        quantity: QUANTITY,
        url: PRODUCT_LINK,
        image: IMAGE_OF_PRODUCT
      },
      {    
        id: SKU_ID_IN_YOUR_SYSTEM,
        name: PRODUCT_NAME,
        price: PRICE,
        quantity: QUANTITY,
        url: PRODUCT_LINK,
        image: IMAGE_OF_PRODUCT
      },
    )
    const shippingAddress = {}
    shippingAddress['houseNo'] = CUSTOMER'S_HOUSE_NO
    shippingAddress['email'] = CUSTOMER'S_EMAIL
    shippingAddress['phoneNo'] = CUSTOMER'S_PHONE_NO
    shippingAddress['firstName'] = CUSTOMER'S_FIRST_NAME
    shippingAddress['lastName'] = CUSTOMER'S_LAST_NAME
    shippingAddress['street'] = CUSTOMER'S_STREET
    shippingAddress['postalCode'] = CUSTOMER'S_POSTAL_CODE
    shippingAddress['city'] = CUSTOMER'S_CITY
    shippingAddress['state'] = CUSTOMER'S_STATE
    shippingAddress['country'] = CUSTOMER'S_COUNTRY // ISO 3166-1-alpha-2
    orderInfo['goodsInfo'] = goodsInfo
    orderInfo['shippingAddress'] = shippingAddress
    payload['orderInfo'] = JSON.stringify(orderInfo)
    
    payload['signType'] = 'RSA'
    payload['merchantNo'] = YOUR_MERCHANT_NO
    payload['notifyUrl'] = ASYNC_NOTIFY_URL
    payload['echoParam'] = ECHO_PARAM
    payload['sign'] = calcRSA(payload)

}

function calcRSA(payload) {
  const data = Object.keys(payload)
    .sort()
    .reduce((obj, key) => {
      obj[key] = payload[key]
      return obj
    }, {})
  var str = ''
  Object.keys(data).forEach((key) => {
    if (data[key] != '' && key != 'sign') {
      str = str + key + '=' + data[key] + '&'
    }
  })
  str = str.substr(0, str.length - 1)
  return new NodeRSA(YOUR_RSA_PRIVATE_KEY, 'pkcs8-private').sign(
    Buffer.from(str),
    'base64',
  )
}

Last updated