签名
Last updated
Last updated
UseePay 使用签名-验签名机制来防止数据传输的过程中被篡改。目前 API 集成 UseePay 支持两种签名方式: MD5, RSA。无论是 MD5 还是 RSA 方式, sign 和 value trim后为空的 key-value 都不参与签名计算过程!
在 UseePay 商户后台的配置中心->密钥管理中点击获取MD5密钥
按照ASCII码生序对请求的 payload 进行排序
按第一步获取的结果,进行key-value 遍历, 对 value trim 后不为空的 key-value 使用 URL 键值对的格式进行拼接(key1=value1&key2=value2...),
第2步取到字符串, 拼接上 &pkey=商户的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的格式为 1024 PKCS8
访问如 http://www.metools.info/code/c80.html 生成密钥对:
注意, 请将公钥字符串中的首行(-----BEGIN PUBLIC KEY-----)与尾行(------END PUBLICK KEY-----)删除, 然后将中间部分格式化成一行粘贴进去
在上图中, 你需要保存 UseePay RSA 公钥, 请求的响应数据, UseePay 会使用 UseePay 的 RSA 私钥进行签名, 并返回 sign 值, 你需要使用 UseePay RSA 公钥进行验签
按照ASCII码生序对请求的 payload 进行排序
按第一步获取的结果,进行key-value 遍历, 对 value trim 后不为空和 key 不为 sign 的 key-value 使用 URL 键值对的格式进行拼接(key1=value1&key2=value2...),
对第2步取到字符串, 用之前生成的商户 RSA 密钥进行签名做 base64, 获取 sign 值
// 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',
)
}