备注:以下代码基于PHP laravel框架,引用了自带的函数。array_get($array, "key")
为数组中取元素,类似于$array["key"]
。快钱后端语言为java,对接快钱时遇到了一些问题,今天整理下,希望可以帮到更多的人。
一、后端拼接唤起支付url
/**
* 快钱一码付(聚合支付)相关配置
*/
$kuaiqian = [
"merchantCode" => "10210xxxxxx", //商户会员号
"merchantId" => "812310xxxxx", //商户编号
"terminalId" => "71075xxxxx", //终端编号
"key" => "xxxxxxx", //支付秘钥
"payUrl" => "https://pay.99bill.com/prod/html/agent-static/index.html", //快钱前端唤起支付url
"returnUrl" => "https://xxx/return_url", //支付成功,前端回调url
]
/**
* 拼接支付参数
* @param $orderNumber
*/
function getPayUrl($orderNumber, $money)
{
$data = [
"requestTime" => date("YmdHis"),
"externalTraceNo" => $orderNumber,
"merchantCode" => array_get($kuaiqian, "merchantCode"),
"merchantId" => array_get($kuaiqian, "merchantId"),
"terminalId" => array_get($kuaiqian, "terminalId"),
"amt" => $money,
"returnUrl" => array_get($kuaiqian, "returnUrl")."?orderNumber=".$orderNumber //前端同步回调地址
];
$sign = kuaiqian_sign($data);
$data["secretInfo"] = $sign;
$string = "";
foreach ($data as $key => $value) {
$string .= $key."=".$value."&";
}
return array_get($kuaiqian, "payUrl")."?".rtrim($string, "&");
}
/**
* 快钱支付签名
*/
function kuaiqian_sign($data)
{
ksort($data);
$res = "";
foreach ($data as $key => $value) {
if (!$value) continue; //参数值为空时不参与签名
$res .= $key."=".$value."&";
}
$stringSignTemp = $res."key=".array_get($kuaiqian, "key");
return strtoupper(md5($stringSignTemp));
}
二、回调签名(和支付、微信不同的是快钱的回调地址需要提前和业务联系配置)
/**
* 支付异步回调
* @param Request $request
*/
function payNotify(PayRepository $payRepository)
{
$request = file_get_contents("php://input");
$request = explode("&", $request);
//将回调数组转为完整数组
foreach ($request as $data) {
$tmp = explode("=", $data);
$result[array_get($tmp, "0")] = urldecode(array_get($tmp, "1"));
}
//支付回调签名验证
$signVerify = kuaiqian_notify_sign_verify($result);
//签名不通过
if (!$signVerify) {
return "1";
}
//系统内部订单号
$orderNumber = array_get($result, "externalTraceNo");
//订单已经支付成功,不需要重复回调
if (array_get($payOrder, "status") != PayOrder::PAY_ORDER_STATUS_NOT) {
return "0";
}
if (array_get($result, "processFlag") === "0") { //支付成功,处理内部业务逻辑
$result = "success"; //处理支付成功以后的业务逻辑
if (!$result) {
return "1";
} else {
return "0";
}
} else { //支付不成功,也不允许再次回调
return "0";
}
}
/**
* 快钱支付接口通知验签结果校验
* @param $datas array 快钱回调完整报文
*/
function kuaiqian_notify_sign_verify($datas)
{
$signature = array_get($datas, "signature"); //获取签名
//获取参与验签的数组节点(array_only()为laravel封装的函数,获取数组中指定键的参数,可以自己封装。)
$datas = array_only($datas, ["processFlag", "txnType", "orgTxnType", "amt", "externalTraceNo", "orgExternalTraceNo",
"terminalOperId", "authCode", "RRN", "txnTime", "shortPAN", "responseCode", "cardType", "issuerId"]);
//节点值为空时屏蔽节点,不需要参与验签
foreach ($datas as $key => $value) {
if ($datas[$key] === "") {
unset($datas[$key]);
}
}
$result = implode("", $datas); //等待验签字符串拼接
$publicKey = openssl_get_publickey(file_get_contents(public_path("xxxx/public.pem"))); #特别强调:验签公钥快钱给的是.cer格式,PHP需要转为pem(openssl x509 -inform der -in xx.cer xx.pem)
return openssl_verify($result, base64_decode($signature), $publicKey);
}
三、后记
快钱后端为Java,导致回调验签的时候费了好大力气才搞定,今天整理了下,需要的伙伴可以试试,有问题可以私我。(快钱做大做强了,但技术对接服务这块真的不怎么样,坑死。)