前一久作了支付宝支付,分享一下接入的详细步骤吧,移动端和服务端demo源码已上传至GitHub,要下载的移步至文章末尾。
先给出支付宝官方文档:https://docs.open.alipay.com/204/105051/html
在App内集成支付宝支付。APP调用支付宝提供的SDK,SDK再调用支付宝APP内的支付模块。若是用户已安装支付宝APP,商家APP会跳转到支付宝中完成支付,支付完后跳回到商家APP内。若是用户没有安装支付宝APP,商家APP内会调起支付宝网页支付收银台,用户登陆支付宝帐户,支付完后展现支付结果。java
地址:https://open.alipay.com/platform/appManage.htm#/apps
android
建立应用后即生成应用的标识APPID
建立指南:https://docs.open.alipay.com/200/105310/
git
从个人应用列表点击应用对应的查看详情按钮进入github
添加完成后,若应用状态为开发中状态,只能在沙箱环境下进行调试。应用申请上线后,会同时申请此列表的功能,接口即生效。web
注:手机端支付能够添加 APP支付 和手机网站支付。APP支付使用原生开发,调用支付宝支付SDK。手机网站支付是在网页中调用支付宝,因此使用h5+mui方式开发APP可以使用此功能,无需跳转至原生。这里根据须要酌情选择。
算法
在功能列表中点击签约,签约后才能正常使用,签约前可以使用沙箱模式进行调试。数据库
以上的步骤能够交给公司相关人员进行申请,开发人员请看下面express
因此须要获取到应用公钥、应用私钥以及支付宝公钥:api
①应用公钥
由商户本身生成的RSA公钥(与应用私钥必须匹配),商户需上传应用公钥到支付宝开放平台,以便支付宝使用该公钥验证该交易是不是商户发起的。
②应用私钥
由商户本身生成的RSA私钥(与应用公钥必须匹配),商户开发者使用应用私钥对请求字符串进行加签。
③支付宝公钥
支付宝的RSA公钥,商户使用该公钥验证该结果是不是支付宝返回的。
步骤:https://docs.open.alipay.com/200/105310#s2
签名专区:https://docs.open.alipay.com/291/106103/
密钥生成工具:https://docs.open.alipay.com/291/106097/
注:使用密钥生成工具生成密钥时,要注意密钥格式,若是服务端使用.Net或其余非java语言,必定要选PKCS1(非JAVA适用),不然后面要凉凉。密钥长度建议选择2048。
使用App支付功能须要在原生中实现,这里以Android为例。接入移动支付须要集成两个SDK,分别是客户端的SDK和服务端的SDK。
SDK下载地址:
客户端https://docs.open.alipay.com/54/104509
服务端https://docs.open.alipay.com/54/106370/
注:为什么须要两个SDK?由于客户端不能含有敏感信息,包括密钥、APPID等,这些东西都必须从服务端获取,包括加签验签过程,因此还须要集成一个服务端给APP调用。
集成方法:https://docs.open.alipay.com/204/105296/
支付宝SDK中提供了一个PayTask类,使用其payV2方法便可发起支付请求。
/** * 支付(加签过程不容许在客户端进行,必须在服务端,不然有极大的安全隐患) * * @param orderInfo 加签后的支付请求参数字符串(主要包含商户的订单信息,key=value形式,以&链接)。 */ private void pay(final String orderInfo) { final Runnable payRunnable = new Runnable() { @Override public void run() { PayTask alipay = new PayTask(MainActivity.this); //第二个参数设置为true,将会在调用pay接口的时候直接唤起一个loading Map<String, String> result = alipay.payV2(orderInfo, true); Message msg = new Message(); msg.what = SDK_PAY_FLAG; msg.obj = result; mHandler.sendMessage(msg); } }; // 必须异步调用 Thread payThread = new Thread(payRunnable); payThread.start(); }
参数:
orderInfo: app支付请求参数字符串,主要包含商户的订单信息,key=value形式,以&链接。由众多请求参数加签以及非对称加密后生成。
具体参数说明请看文档:https://docs.open.alipay.com/204/105465/
因此发起支付请求的重点在于获取orderInfo,也就是从服务端获取加签结果,加签过程不容许在客户端进行,不然可能被反编译,形成严重的后果。因此加签过程请看下面服务端(.Net)SDK集成的第(1)条。
调用支付宝支付后,将会收到同步通知和异步通知。若是过程当中取消支付则只会收到同步通知。
同步通知:支付宝sdk对商户的请求支付数据处理完成后,会将结果同步反馈给app端。在支付回调中便可获取支付结果信息。
异步通知: 对于App支付产生的交易,支付宝会根据原始支付API中传入的异步通知地址notify_url,经过POST请求的形式将支付结果做为参数通知到商户系统。
注: 手机端同步通知有可能存在获取不到的状况,如手机关机,应用crash等状况,因此手机端同步回调只做为支付结果提示。真正的支付成功逻辑将在支付宝异步通知(服务端)中作处理,请看下面服务端(.Net)SDK集成的第(2)条。
so,手机端只作同步通知处理,以下:
Map<String, String> result = alipay.payV2(orderInfo, true);
result就是返回的同步回调结果,里面的resultStatus是支付状态码,若是是9000则支付成功。
if (TextUtils.equals(resultStatus, "9000")) { // 该笔订单是否真实支付成功,须要依赖服务端的异步通知。 showAlert(MainActivity.this, "支付成功" + payResult); } else { // 该笔订单真实的支付结果,须要依赖服务端的异步通知。 showAlert(MainActivity.this, "支付失败" + payResult); }
若是使用混合开发(h5+mui+原生),还需跳转至mui页面,则可以使用js回调函数将同步通知传入mui端进行后续处理,如:
// 调用方法将原生代码的执行结果返回给js层并触发相应的JS层回调函数 JSUtil.execCallback(mWebview, CallBackID, resultStatus, JSUtil.OK, false);
集成方法:https://docs.open.alipay.com/54/106370/
为了便于支付宝异步接口调用,这里服务端将使用webApi,服务端主要工做为加签、验签(异步通知验证)以及更改订单支付状态。
核心步骤:
//从pem文件中读取 APP_PRIVATE_KEY = GetCurrentPathByAbs() + "rsa_private_key.pem"; ALIPAY_PUBLIC_KEY = GetCurrentPathByAbs() + "rsa_alipay_public_key.pem"; //最后一个参数为false直接将私钥内容写入代码,true从pem文件中读取 IAopClient client = new DefaultAopClient(gateway, APPID, APP_PRIVATE_KEY, format, version, sign_type, ALIPAY_PUBLIC_KEY, CHARSET, true); //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称如:alipay.trade.app.pay AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest(); //SDK已经封装掉了公共参数,这里只须要传入业务参数。如下方法为sdk的model入参方式(model和biz_content同时存在的状况下取biz_content)。 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); model.Body = body; model.Subject = subject; model.TotalAmount = total_amount; model.ProductCode = product_code; model.OutTradeNo = out_trade_no; model.TimeoutExpress = timeout_express; request.SetBizModel(model); request.SetNotifyUrl(notify_url); //这里和普通的接口调用不一样,使用的是sdkExecute AlipayTradeAppPayResponse response = client.SdkExecute(request); string resp = response.Body; return resp;
支付宝服务端SDK中提供了一个SdkExcute方法,须要传入对应的request类AlipayTradeAppPayRequest。实例化IAopClient对象时须要传入请求网关(gateway)、APPID、应用私钥、支付宝公钥、调用的接口版本、编码方式、签名算法类型以及是否从文件中读取密钥的一个bool类型值。
其中,签名算法类型应和配置密钥时选择的类型一致,另外2018年1月5号以后建立的应用都须要使用RSA2,也就是sign_type=RSA2,不然会加签失败。最后一个bool型参数,为false直接从代码中读取密钥,为true则从pem文件中读取。
若是以为密钥放在代码中不够安全的话,建议将密钥存储为pem文件,执行加签过程时从文件中读出,作法以下:
pem文件是有格式的,就像这样
-----BEGIN RSA PRIVATE KEY----- MIIEogIBAjayyr4gU38hr/EYnXdbEfbaGkdVnvf6Y+9zWkkiPcNq-----这里是密钥内容 -----END RSA PRIVATE KEY-----
生成pem文件须要使用openssl.exe这个可执行文件,固然也能够copy个pem文件替换下里面的密钥内容,不过这样有可能会致使格式乱了。openssl.exe在密钥生成工具的openssl的bin目录下,双击便可打开。
生成应用私钥pem文件,输入命令:genrsa -out rsa_private_key.pem 2048
生成应用公钥pem文件,输入命令:rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
支付宝公钥须要上传应用公钥获取,若是不使用pem文件,代码中直接放上支付宝公钥就行,若是要使用pem文件,能够将应用公钥的pem文件复制一份,将密钥内容换成支付宝公钥的,格式以下。
-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAADCBi----------这里是支付宝公钥 -----END PUBLIC KEY-----
注:上面密钥的格式默认为PKCS1的,若是使用PKCS8(Java适用)别忘记执行转码命令,不然也要凉凉的。若是使用沙箱模式请将密钥换成沙箱版进行测试。
首先获取存放密钥文件的路径,为了防止出现意外,可获取文件的绝对路径,以下:
/// <summary> /// 获取私钥公钥的路径(绝对路径) /// </summary> /// <returns></returns> private static string GetCurrentPathByAbs() { return HttpRuntime.AppDomainAppPath.ToString() + "rsa/"; }
获取到文件路径后传入IAopClient的构造函数中,并将最后一个参数置为true便可。
IAopClient client = new DefaultAopClient(gateway, APPID, APP_PRIVATE_KEY, format, version, sign_type, ALIPAY_PUBLIC_KEY, CHARSET, true);
当支付宝发送异步通知时,会将支付结果的信息异步返回至服务端,服务端须要进行验签操做,验证请求是不是支付宝发送,并利用支付宝公钥进行比对,保证交易的安全性和正确性。主要步骤以下:
①提供异步调用接口
支付宝异步通知将以post的方式发起请求,因此咱们须要编写一个webapi接口,并保证接口的正确性,以下:
/// <summary> /// 异步验签(客户端支付后,支付宝服务器将异步调用此方法) /// 实际支付逻辑在此操做,支付宝服务端将保证调用到此接口 /// </summary> /// <returns></returns> [HttpPost] public string GetAsynchronousYanQian() { return AlipayUtil.AsynchronousYanQian(GetRequestPost()); }
这个接口地址即是加签过程当中传入的异步通知地址notify_url
②获取异步通知结果并验签
官方文档地址:https://docs.open.alipay.com/54/106370/
上面这个连接支付宝介绍了如何获取通知参数并验签。可是部分代码是错的,请看我写的。
获取支付宝异步通知结果以下:
/// <summary> /// 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组 /// request回来的信息组成的数组 /// </summary> /// <returns></returns> public Dictionary<string, string> GetRequestPost() { int i = 0; IDictionary<string, string> sArray = new Dictionary<string, string>(); NameValueCollection coll; coll = Request.Form; String[] requestItem = coll.AllKeys; for (i = 0; i < requestItem.Length; i++) { sArray.Add(requestItem[i], Request.Form[requestItem[i]]); } return (Dictionary<string, string>)sArray; }
验签:
验签过程支付宝AlipaySignature类提供了验签方法RSACheckV1和RSACheckV2,区别就不细说,这里使用RSACheckV1方法,第一个参数即是支付宝返回的异步通知结果,第二个参数传入支付宝公钥,一样最后一个参数传false从代码读取支付宝公钥,传true从pem 文件中读取。
bool flag = AlipaySignature.RSACheckV1(result, ALIPAY_PUBLIC_KEY, CHARSET, sign_type, true);
验签结果返回一个bool值,若是验签成功返回true,不然false。
③通知支付宝
支付宝异步通知调用接口后,若是未收到成功反馈,将会在一段时间内重复发送异步通知,以保证服务端接收到异步通知。因此当验签成功并真正的改变订单支付状态后,须要给支付宝返回success。若是反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。通常状况下,25小时之内完成8次通知(通知的间隔频率通常是:4m,10m,10m,1h,2h,6h,15h)。
if (flag) { //验签成功,将数据库中订单的支付状态改变 if (ChangePayState()) { //若是数据库插入成功,通知支付宝已收到通知 return "success"; } else { return "fail"; } } else { return "fail"; }
注:若是在改变订单支付状态时须要的某些参数没法获取,能够将其拼接在加签过程当中某些不是很必要的参数里,支付宝将在异步通知中返回。
以上即是支付宝支付的实现步骤,包括了移动端(原生)和服务端(.Net)。Demo已上传至GitHub,有兴趣的能够下载:
移动端:https://github.com/yangxch/AlipayDemo
服务端:https://github.com/yangxch/AlipayServerAPIDemo
原创不易,转载请注明:http://www.javashuo.com/article/p-vlezjhag-mo.html