我们一般会看见这四种密钥
rsa_private_key 商户私钥 :生成后要保存在服务端,绝对不能保存在客户端,也绝对不能从服务端下发
rsa_public_key 商户公钥 :由我们自己生成的RSA公钥(必须与商户端私钥是一对),生成后需要填写在支付宝开放平台
alipay_private_key 支付宝私钥 :支付宝私钥是支付宝自己生成的,由他们自己保存的
alipay_public_key 支付宝公钥:支付宝公钥和支付宝私钥是一对,也是支付宝生成的,当我们把商户端公钥填写在支付宝开放平台后,平台就会给我们生成一个支付宝公钥,我们可以复制下来保存在服务端
当我们商户端和支付宝互相发布了公钥之后,我们商户端手里就有商户端私钥和支付宝公钥两个密钥,支付宝手里也有商户端公钥和支付宝私钥两个密钥。那么这两端通信就是
①:商户上传自己的商户公钥到支付宝服务器
②:使用商户私钥加密请求参数
③:加密以后的参数请求到支付宝
④:支付宝服务器使用商户上传的商户公钥,解密商户请求参数,并处理支付结果
⑤:对商户支付结果使用支付宝私钥加密
⑥:商户使用支付宝公钥验签支付返回的支付结果
(商户端)明文订单信息+商户端私钥加密=加密订单信息
(---->传递---->)
(支付宝)加密订单信息+商户端公钥解密=明文订单信息
建议开发者直接依赖支付宝服务端返回给我们服务端的异步支付结果(即第12步),而忽略同步支付结果,因为同步结构有可能会收不到。但是异步结果,支付宝服务器会根据自己的策略每隔一段时间给我们通知一次,直到我们回复他 SUCCESS。退款和付款一样如此,注意,退款成功回调和付款成功回调是一个地址。
以TP5为例
我将下载下来的支付宝sdk放进了框架的extend目录中,同时将常用方法封装成了一个类
class AlipayService
{
public function __construct()
{
$this->conf=array(
'notify_url'=>config('alipay.notify_url'),//必须返回success.此方法中需要做支付宝异步验签,确定是支付宝发送给我的消息
'return_url'=>config('alipay.return_url'),//支付成功跳转
'gatewayUrl'=>config('alipay.gatewayUrl'),
'appId'=>config('alipay.app_id'),
'rsaPrivateKey'=>config('alipay.merchant_private_key'),
'alipayrsaPublicKey'=>config('alipay.alipay_public_key')
);
}
/**
* notes:支付接口,pageExecute 是PC和手机网站 有页面输出,SdkExecute APP服务端的
* @param $order
* @param string $type app,wap,api
* @return string
*/
public function pay($order,$type='app'){
//require_once('/extend/alipay/aop/AopClient.php');
//require_once('/extend/alipay/aop/request/AlipayTradeAppPayRequest.php');
import('alipay/aop/AopClient', EXTEND_PATH);
import('alipay/aop/request/AlipayTradeAppPayRequest', EXTEND_PATH);
import('alipay/aop/request/AlipayTradeWapPayRequest', EXTEND_PATH);
import('alipay/aop/request/AlipayTradeQueryRequest', EXTEND_PATH);
import('alipay/aop/request/AlipayTradePagePayRequest', EXTEND_PATH);
$notify_url=$this->conf['notify_url'];
$return_url=$this->conf['return_url'];
$aop = new \AopClient();
$aop->gatewayUrl = $this->conf['gatewayUrl'];
$aop->appId = $this->conf['appId'];
$aop->rsaPrivateKey = $this->conf['rsaPrivateKey'];
$aop->alipayrsaPublicKey = $this->conf['alipayrsaPublicKey'];
$aop->apiVersion = '1.0';
$aop->postCharset = 'utf-8';
$aop->signType = "RSA2";
$aop->format = "json";
/* $bizcontent = json_encode([
'body'=>'商品信息',
'subject'=>'衣服',
'out_trade_no'=>'123456',//此订单号为商户唯一订单号
'total_amount'=> '0.01',//保留两位小数
'product_code'=>'QUICK_MSECURITY_PAY'
]);*/
if($type=='app'){
//app端使用
$order['product_code']="QUICK_MSECURITY_PAY";
$bizcontent=json_encode($order);
$request = new \AlipayTradeAppPayRequest();
//支付宝回调
$request->setNotifyUrl($notify_url);
$request->setBizContent($bizcontent);
//这里和普通的接口调用不同,使用的是sdkExecute
$response = $aop->sdkExecute($request);
return $response;
}elseif($type=='wap'){
//移动端使用
$order['product_code']="QUICK_WAP_WAY";
$bizcontent=json_encode($order);
$request = new \AlipayTradeWapPayRequest();
$request->setNotifyUrl($notify_url);
$request->setBizContent($bizcontent);
$response = $aop->pageExecute($request);
return $response;
}elseif($type=='page'){
//当面付,二维码,pc端使用
$order['product_code']="FAST_INSTANT_TRADE_PAY";
$bizcontent=json_encode($order);
$request = new \AlipayTradePagePayRequest();
$request->setNotifyUrl($notify_url);
$request->setReturnUrl($return_url);
$request->setBizContent($bizcontent);
$response = $aop->pageExecute($request);
return $response;
}
}
/**
* notes:退款
* @param $order
* @throws \Exception
*/
public function trade_refund($order)
{
import('alipay/aop/AopClient', EXTEND_PATH);
import('alipay/aop/request/AlipayTradeRefundRequest', EXTEND_PATH);
$aop = new \AopClient();
$aop->gatewayUrl = $this->conf['gatewayUrl'];
$aop->appId = $this->conf['appId'];
$aop->rsaPrivateKey = $this->conf['rsaPrivateKey'];
$aop->alipayrsaPublicKey = $this->conf['alipayrsaPublicKey'];
$aop->apiVersion = '1.0';
$aop->postCharset = 'utf-8';
$aop->signType = "RSA2";
$aop->format = "json";
$bizcontent=json_encode($order);
$request = new \AlipayTradeRefundRequest();
$request->setBizContent($bizcontent);
$response = $aop->execute($request);
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
$resultCode = $response->$responseNode->code;
if(!empty($resultCode)&&$resultCode == 10000){
return "success";
} else {
return "fali";
}
}
}
调用方法如下
/**
* notes:支付宝支付
* @param Request $request
*/
public function diagnosis_alipay(Request $request)
{
$order=[
'body'=>'商品信息',
'subject'=>'衣服',
'out_trade_no'=>'kof99',//此订单号为商户唯一订单号
'total_amount'=> '0.01',//保留两位小数
];
$type='app';
$alipay=new alipayService();
$res=$alipay->pay($order,$type);
echo $res;
}
/**
* notes:支付宝退款
* @param Request $request
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function alipay_trade_refund(Request $request)
{
$data['refund_reason']='客户订单取消-退款';
$data['refund_amount']='0.01';
$data['out_trade_no']='DN202101051054280HwV';//商户自己平台唯一订单号
$alipay=new alipayService();
$res=$alipay->trade_refund($data);
if($res=='success'){
//退款成功,更改订单状态
.................
.................
.................
return Send::successMsg('订单退款成功');
}else{
return Send::errorMsg(500,'退款失败');
}
}
回调也写在了一个了类中
class Pays
{
public function alipay_notify(Request $request)
{
import('alipay/aop/AopClient', EXTEND_PATH);
$aop = new \AopClient();
$aop->alipayrsaPublicKey = config('alipay.alipay_public_key');//公钥
//此处验签方式必须与下单时的签名方式一致
$flag = $aop->rsaCheckV1($_POST, NULL, "RSA2");
if(!empty($_POST) && $flag)
{
/**
①验签通过后核实如下参数out_trade_no、total_amount、seller_id
②修改订单表
**/
$order=DB::name('hospital_diagnose_order')->where('orderid',$_POST['out_trade_no'])->find();
if($order){
if(config('alipay.app_id')==$_POST['app_id']) {
if ($order['amount'] == $_POST['total_amount']) {
if($_POST['trade_status'] == 'TRADE_SUCCESS') { //订单已完成
//验参成功,更新订单状态,判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_amount与通知时获取的total_fee为一致的
//如果有做过处理,不执行商户的业务程序
if($order['status']=='0'){//订单状态为待支付
$update['id']=$order['id'];
$update['paytime']=$_POST['gmt_payment'];
$update['status']='1';
$update['payment']='支付宝';
$update['trade_no']=$_POST['trade_no'];
DB::name('hospital_diagnose_order')->update($update);
//告诉支付宝回调执行成功
echo "success";
}
}if($_POST['trade_status'] == 'TRADE_FINISHED'){ //即时到账普通版。 普通版不支持支付完成后的退款操作,即用户充值完成后,该交易就算是完成了,这笔交易就不能再做任何操作了
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_amount与通知时获取的total_fee为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
}else{
echo "fail";
}
}
}
}
}else{
echo "fail";
}
}
}