Android 第三方支付

 
参看支付宝官方文档《安全支付服务 Android 应用开发指南》

一、安全支付服务简介:

(一)、安全支付服务介绍

        安全支付服务是安装在本地 Android 操作系统上的一个组件,主要用来向其它的应用程 序提供便捷、安全以及可靠的支付服务。正如平常系统上所提供的其它服务,如电子邮件和电话服务一样。

 

(二)、安全支付业务流程图

Android 第三方支付_第1张图片

 

(三)、调用安全支付数据的流程

  1. 购买 Buy 
  2. 生成订单 Create order info 
  3. 订单签名 Sign order 
  4. 调用安全支付服务 Call SecurePayment 
  5. 回调支付结果 Callback payment result 
  6. 商户验签支付结果 Merchant check the signature of payment result 
  7. 结束 Finish

 

 

二、安全支付接入流程

(一)接入前期准备

        接入前期准备工作包括商户签约密钥配置
1、商户签约
        首先,商户需要在 https://ms.alipay.com 进行注册,并签约安全支付服务。签约成功后可获取支付宝分配的合作商户 ID(PartnerID),账户 ID(SellerID),如图:

 

2、密钥配置
        签约成功后,商户可登陆 https://ms.alipay.com 获取商户账号对应的支付宝公钥,具体获取步骤请见 “RSA 密钥详解”。接着,商户生成商户公钥商户私钥(具体生成步骤请见 “ RSA 密钥详解”),并登陆https://ms.alipay.com,上传商户公钥(具体上传步骤请见 “ RSA 密钥详解”)。至此,接入前期准备工作完成,下一节将使用 demo 测试准备工作是否正确。

 

(二)、 Demo

【注意:请勿在模拟器下测试 demo,否则可能导致付款账户被锁定!】

 

1、Demo 配置运行
步骤 1:  Demo 导入


步骤 2:  

        打开“PartnerConfig.java”文件,按照注释添加商户账号信息,具体包括:合作商户 ID、账户 ID、支付宝公钥(即服务器公钥)、商户公钥、商户私钥。

 

        示例代码:

// 合作身份者id,以2088开头的16位纯数字
public static final String PARTNER = "2088112738535023";
// 收款支付宝账号
public static final String SELLER = "[email protected]";
// 商户私钥,自助生成
public static final String RSA_PRIVATE = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAM99AHDnDbybtO/z/XqieV1Y1jHH3Y5m9XCGNXPMBSkIU5nzc/jLmrl034GnlaoB5q3OH2Ze99Tet816OmWfDqmCoZZIZ8g3cw8ntgM92lxwAd97Lh76NtwDQ5KN1slBw2ZUkszyvNq/VGyjqiE/270JwQWslo9qMHaPldpL/Z2tAgMBAAECgYBAYujtIDYaDjOCtrM1CBAjUHr/bacqFncZmPwjV+9OAWB4CJ03Wm9EF6l4AXonDHn5+1mxGc1MSGS/JavTdx1EG0uPyDc16BpSWbvlmKsPQgUKyAs6Fugyl11PowIDvf29geukQcKLVwhgLYHPd5hH1GO1UAF+cj/IsjIWFaGhoQJBAPtIjh8p3DBvAbgvh5fBEwjX0b6q95jkbbfdQZS4YgWFdoaP70Zq3KYw3dHVGgLJxWGxCSW2wEwoHuLzZjNwyeUCQQDTYgGOJYM0PcMkJVnEhy4S2/+mQb7WBU+mBWooUK61lUpajZuBj8xBZggrHkPU4iQB/wWOVCc8XdPaq9ctw6gpAkBH6Sya6HzV836XeiqgmCVdW33vxbeTrpNjkdMJv3Z1xAr2WUyNZ1l7yfJA8W4/LATrfyFyBImlgbnNEwDFadqtAkAr6EakbRxUxKN9JZkA3odueW4f7bYjJJVHygYj+6Zep3T7XEC559Gon/YAZtf2J0cNdxiDWO2Rd3fjCyC2K9cJAkBEQP43KekFeDdADP0QDNhG/bWfqWHfVim46EOxgJr8yw8Kr9SfinQfQZvPKPEFBvorK90/jtsukmwvEaaK+WZj";
// 支付宝公钥
public static final String RSA_PUBLIC = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnxj/9qwVfgoUh/y2W89L6BkRAFljhNhgPdyPuBV64bfQNN1PjbCzkIM6qRdKBoLPXmKKMiFYnkd6rAoprih3/PrQEB/VsW8OoM8fxn67UDYuyBTqA23MML9q1+ilIZwBC2AQ2UBVOrFXfFl75p6/B5KsiNG9zpgmLCUYuLkxpLQIDAQAB";

 

步骤 3:
        在真机或者模拟器上运行项目(下图以模拟器为例),首次启动时,由于系统未安装安全支付服务,将出现以下提示:

Android 第三方支付_第2张图片

图:安全支付安装确定

 

    此时,可以选择“确定”进行安装,安装后该提示不会再出现。此时点击任意商品进行购买,即启动安全支付:

图:  安全支付启动

 

        首次运行安全支付服务,会进行安全认证,此时选择“支付宝账户”付款(注意:付款用的账户应为某一真实账户,交易金额也是真实的!),输入账户信息,按照提示一步步进行:

图: 安全认证

 

        完成安全认证后,若出现如下提示,说明密钥配置有误,请仔细阅读 “RSA 密钥详解”

Android 第三方支付_第3张图片

图:验签错误-支付失败

 

        若出现“确认支付”页面,说明密钥配置无误,接入前期准备工作全部正确完成。接下来将正式进行安全支付的接入集成。

 

2、Demo 结构说明

类名 说明 
AlixDemo  主 Activity

Base64

Base64 编码类,签名及验签,必须

MobileSecurePayer

封装了对安全支付的调用,可参考性较强

MobileSecurePayHelper

实现安全支付插件的检测,更新下载,安装,可参考性较强 

Networkmanager 网络连接管理 

PartnerConfig 

商户账户信息配置 

ResultChecker

AlixPay 返回结果的解析处理,可参考性较强 

Rsa 

RSA 签名验签类,必须

 

 

(三)、安全支付集成

       本节指导在商户APP项目中集成安全支付,关键代码以 Demo 为例。

1、步骤 1:添加 jar 文件

        添加 demo 中的 alipay_msp.jar 包添加工程中。

 

2、步骤 2:初始化安全支付服务
        在调用安全支付进行支付前,需要先初始化安全支付服务。

 

3、步骤 3:订单数据生成
        在调用安全支付时,需要提交订单信息 orderInfo 其中参数以“key=value”形式呈现,参数之间以“&”分割,所有参数不可缺。

 

partner="2088002007260245"&seller="2088002007260245"&out_trade_no="500000000006548"&subject=" 商 品 名 称 "&body=" 这 是 商 品 描 述"&total_fee="30"¬ify_url="http://notify.java.jpxx.org/index.jsp"&sign="kU2Fa3x6V985g8ayTozI1eJ5fHtm8%2FJGeJQf9in%2BcVmRJjHaExbirnGGKJ%2F7B63drqc4Kjlk%2FSg6vtSIkOtdvVBrRDpYaKxXVqkJTzRYgUwrrpMudbIj9aMS2O3dHG0GPyL4Zb6jKDYXHabGG0aBJY3QA7JuTJ23t6SqV%2B5f1xg%3D"&signtype="RSA"

 

        其中 sign 值的生成,需要特别注意的是:对数据签名后得到的 sign值必须进行 URLEncode,之后才可作为参数。

 

4、步骤 4:调用安全支付
        准备好参数后,即可调用安全支付进入支付流程并获得调用结果,代码如下:
        result = mAlixPay.pay(orderInfo);
        AliXPay 函数具体说明请见 AlixPay 方法描述。

 

5、步骤 5:支付结果获取和处理
        调用安全支付后,将通过两种途径获得支付结果:
1)、 AliXpay.pay()方法的返回。该方法将返回表示支付结果的字符串
2)、支付宝服务器通知。商户需要提供一个 http 协议的接口,包含在参数里传递给安全支付,即 notify_url。支付宝服务器在支付完成后,会用 POST 方法调用 notufy_url,以 xml 为数据格式传输支付结果。

 

(四)、应用发布
        目前,我们为第三方应用客户端提供了两种集成安全支付服务的方式。第一种是运行时安装,即将安全支付服务安装包 apk 与第三方应用客户端整合在一起,在恰当的时机,由第三方应用客户端释放并安装安全支付服务安装包 apk。另一种则称为动态下载安装,在此种情况下,安全支付服务安装包 apk 是预先存放在约定的远程服务器中,第三方应用客户端可以从此处下载 apk 并进行安装。
        为了提升用户体验,避免捆绑安装旧版本的安全支付服务之后,接着又需要重新升级并安装成最新版本,我们目前推荐结合使用以上两种集成方式。在最新的 demo 中,会首先连接支付宝服务器,检测并判断捆绑在第三方客户端中的 alipay_plugin.apk 是否为最新版本,如果是,则直接安装。如果捆绑在第三方客户端中的 alipay_plugin.apk 不是最新版本,则从服务器中下载最新版本的安装包,然后进行安装。

 

1、运行时安装
        运行时安装的具体步骤如下所示:
1) 将 alipay_plugin.apk 作为资源复制到第三方应用工程中的 assets 目录。
2) 第三方应用在需要付款时(或者其它恰当时机),先检测安全支付服务是否已经安装。如果尚未安装,则从 assets 目录中提取 alipay_plugin.apk 到手机存储。
3) 安装手机存储中的安全支付服务 apk。

 

2、动态下载安装
        动态下载安装的具体步骤如下所示:
1) 由支付宝预先将安全支付服务 apk 放置到约定的远程下载服务器。
2) 第三方应用在需要付款时(或者其它恰当时机),先检测安全支付服务是否已经安装。如果尚未安装,则从约定的远程下载服务器提取 alipay_plugin.apk 到手机存储。
3) 安装手机存储中的安全支付服务 apk。

 

 

三、RSA 详解

(一)、RSA 和 OpenSSL 介绍

1、什么是 RSA?

        RSA 是一种非对称的签名算法,即签名密钥(私钥)与验签密钥(公钥)是不一样的,私钥用于签名,公钥用于验签。在与支付宝交易中,会有 2 对公私钥,即商户公私钥,支付宝公钥。

  • 商户公私钥:由商户生成,商户私钥用于对商户发往支付宝的数据签名;商户公钥需要上传至支付宝,当支付宝收到商户发来的数据时用该公钥验证签名。
  • 支付宝公钥:支付宝提供给商户,当商户收到支付宝发来的数据时,用该公钥验签。

 

2、为什么要用 RSA?
        使用这种算法可以起到防止数据被篡改的功能,保证支付订单和支付结果不可抵赖(商户私钥只有商户知道)。

 

3、什么是 OpenSSL

        一句话概括:OpenSSL 是基于众多的密码算法、公钥基础设施标准以及 SSL 协议安全开发包。

 

4、为什么要用 OpenSSL?

        通过 OpenSSL 生成的签名和内置的算法可以做到跨平台,这样在不同的开发语言中均可以签名和验签。

 

(二)、RSA 密钥详解【重要

 

1、找到生成 RSA 密钥工具

 

(1)下载开发指南和集成资料,您能看到此文档说明指南和集成包已经下载了。
(2)解压下载的压缩包(WS_SECURE_PAY),找到并解压 openssl-0.9.8k_WIN32(RSA 密钥生成工具).zip 工具包

 

2、生成商户密钥并获取支付宝公钥
(1) 生成原始 RSA 商户私钥文件

 

        假设解压后的目录为 c:\alipay,命令行进入目录 C:\alipay\bin,执行“openssl genrsa -out rsa_private_key.pem 1024”,在 C:\alipay\bin 下会生成文件 rsa_private_key.pem,其内容为原始的商户私钥(请妥善保存该文件),以下为命令正确执行截图:

 

图 3- 3 生成原始 RSA 商户私钥文件

 

(2) 将原始 RSA 商户私钥转换为 pkcs8 格式
        命令行执行“ openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt”得到转换为 pkcs8 格式的私钥。复制下图红框内的内容至新建 txt 文档,去掉换行,最后另存为“private_key.txt”(请妥善保存,签名时使用)。

 

图 3- 4 转换私钥格式

 

(3) 生成 RSA 商户公钥

        命令行执行“ openssl rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem”,在 C:\alipay\bin 文件夹下生成文件 rsa_public_key.pem。接着用记事本打开rsa_public_key.pem,复制全部内容至新建的 txt 文档,删除文件头“-----BEGIN PUBLIC KEY-----”与文件尾“-----END PUBLIC KEY-----”及空格、换行,如下图。最后得到一行字符串并保存该 txt 文件为“public_key.txt”。

 

图 3- 5 生成公钥

 

(4) 上传商户公钥至支付宝
        浏览器访问 https://ms.alipay.com/index.htm 并用签约帐号登录,点击菜单栏“我的产品”,右侧点击“密钥管理”,见下图红色框内图 3- 6 商户公钥上传。点击“上传”,选择步骤(3)生成的“public_key.txt”并完成上传。

 

(5) 获取 RSA 支付宝公钥
        成功上传公钥至支付宝后,页面显示如下:
图 3- 7 支付宝公钥获取
        其中红色框内部分即支付宝公钥,请复制至新建 txt 文档,去掉换行和空格,妥善保存(用于验签收到的支付宝通知)。

 

 

(三)、RSA 签名和验签【重要
        【建议:签名和验签尽量在商户服务器端进行,同时一些敏感数据(如公私钥等)也应存储在服务器端,避免可能的安全隐患。】

 

1、RSA 签名
(1) 在项目中添加下面的类:

  • Base64.java
  • Rsa.java//包含了签名验签等方法

 

(2) 生成商品订单:
        可参考 Demo 中 AlixDemo.java 的方法:
        private String getOrderInfo()
例子:出售商品(subject)“Iphone4”,价格(total_fee)“1”元,外部交易号(out_trade_no)“zzzz”,商品描述(body)为“秒杀”,订单支付完成通知 URL(notify_url)为 http://notify.java.jpxx.org/index.jsp

 

则生成如下商品信息字串:
partner="xxxx"&seller="yyyy"&out_trade_no="zzzz"&subject="Ipone4"&body="秒杀"&total_fee="1"¬ify_url="http://notify.java.jpxx.org/index.jsp"

 

(4) 对商品信息进行 RSA 签名
        可使用 Demo 中 Rsa.java 的方法:
        public static String sign(String content, String privateKey)
        String content:待签名字符串
        String privateKey:商户私钥(pkcs8 转换后的商户私钥)
        返回值:签名值(传递给安全支付前需要 URL 编码,样例中未编码)
partner="xxxx"&seller="yyyy"&out_trade_no="zzzz"&subject="Ipone4"&body="秒杀"&total_fee="1"¬ify_url="http://notify.java.jpxx.org/index.jsp"&sign_type="RSA"&sign="O0I1APPVQcK5bbSgdeFx9HB3Yu/U2+akTZ3T0/P7v3g7XD7TsQCprb6O9Nybr8CDIrztdUseQN/TCXuEvCU2cvCt1xX9UUyI6fOxXxQFlDWx7IE2S7Zo5wOeVWmMBnCQCV8iDjcNxGHwhtCT09bVVf0wbaOiHXvAYzWlvPhyR+0="

 

2、RSA 验签
(1) 使用 RSA 类进行验签:
        public static boolean doCheck(String content, String sign, String publicKey)
        String content:待验签的字符串(红色部分)
        String sign:签名值(蓝色部分)
        String publicKey:支付宝公钥
        返回值:验签成功则返回true,反之返回false.
        以下是一个订单支付成功完整信息的示例:

 

resultStatus={9000};
result={partner="2088002007260245"&seller="2088002007260245"&out_trade_no="600000000006891"&subject="商品名称"&body="这是商品描述"&total_fee="1"¬ify_url="http%3A%2F%2Fnotify.java.jpxx.org%2Findex.jsp"&success="true"&sign_type="RSA"&sign="O0I1APPVQcK5bbSgdeFx9HB3Yu/U2+akTZ3T0/P7v3g7XD7TsQCprb6O9Nybr8CDIrztdUseQN/TCXuEvCU2cvCt1xX9UUyI6fOxXxQFlDWx7IE2S7Zo5wOeVWmMBnCQCV8iDjcNxGHwhtCT09bVVf0wbaOiHXvAYzWlvPhyR+0="}

 

备注:result返回的json字串需要处理转义字符(可参考Demo中checkSign函数的处理方式)否则可能导致验签无法通过。

 

(2) 为了方便商户接入安全支付服务,我们将签名和验签的方法封装成 Rsa.java 提供给大家使用,可从 demo 中提取。

 

 

四、通知结果

(一)、AlixPay 方法返回的结果

        支付结果的处理可以参考 Demo 中的类 ResultChecker.java。

        结果信息详细描述如下:


结果判断说明:
需要通过 resultStatus 以及 result 字段的值来综合判断并确定支付结果。在resultStatus=9000,并且 success="true"以及 sign="xxx"校验通过的情况下,证明支付成功。其它情况归为失败。较低安全级别的场合,也可以只通过检查 resultStatus 以及success="true"来判定支付结果。以下为订单支付成功的完成信息示例:
partner=""&seller=""&out_trade_no=""&subject=""&body=""&total_fee="30"¬ify_url=""&success="true"&sign_type="RSA"&sign="xxx"

 

 

(二)、notify_url 通知说明

1、什么是 Notify_url

        支付宝通过访问商户提供的地址的形式,将交易状态信息发送给商户服务器。商户通过支付宝的通知判断交易是否成功,具体如下:

        商户地址:提供一个 http 的 URL(例:http://www.partnertest.com/servlet/NotifyReceiver),支付宝将以 POST 方式调用该地址。
        通知触发条件:交易状态发生改变,如交易从“创建”到“成功”或“关闭”。
        商户返回信息:商户服务器收到通知后需返回纯字符串“success”,不能包含其他任何HTML 等语言的文本。
        通知重发:若支付宝没有收到商户返回的“success”,将对同一笔订单的通知进行周期性重发 (间隔时间为:2 分钟,10 分钟,10 分钟,1 小时,2 小时,6 小时,15 小时共 7 次)。
        交易判断条件:收到 trade_status=TRADE_FINISHED(如果签有高级即时到帐协议则trade_status=TRADE_SUCCESS)的请求后才可判定交易成功(其它 trade_status 状态请求可以不作处理)

 

2、Notify_url 接收数据示例

Notify_data 参数说明

参数名 说明 
trade_status  

用于判断交易状态,值有:

TRADE_FINISHED:表示交易成功完成

WAIT_BUYER_PAY:表示等待付款

TRADE_SUCCESS:表示交易成功(高级即时到帐)

total_fee

交易金额

subject

商品名称

out_trade_no

外部交易号(商户交易号)

trade_no 支付宝交易号

gmt_create

交易创建时间

gmt_payment

交易付款时间

若交易状态是“WAIT_BUYER_PAY”则无此参数

 

 

五、常见问答
1、客户端验签,报“订单信息被篡改”是什么问题?
        可能有以下2种情况
a) 有可能数据在传输过程中被黑客截取和篡改
b) 检查plaintext(待签名的字符串)中是否有以下四个符号,如果参数当中包含了这四个字符也会报“订单信息被篡改”:

  • +加号
  • &连接符
  • “双引号
  • =等号

 

2、客户端调用安全支付时对 body 和 subject 进行 URLEncode 会报签名错误,到底哪些需要URLEncode?
        调用安全支付接口时,只需要对参数sign进行URLEncode,其他参数都不能URLEncode,安全支付服务插件会对所有参数进行URLEncode,所以不用担心中文乱码。

 

3、上传商户公钥报格式错误怎么办?
        首先确认上传的位置是否是RSA的下面,注意不要是DSA,无线目前不支持DSA加密;另外请检查上传的文件中是否去除注释、空格、换行等,必须是一行的字符串。

 

4、 错误代码列表

错误编号 说明 
9000  操作成功

4000

系统异常

4001

数据格式不正确

4003

该用户绑定的支付宝账户被冻结或不允许支付

4004 该用户已解除绑定

4005

订单支付失败

4006

AlixPay 返回结果的解析处理,可参考性较强 

4010

重新绑定账户

6000

支付服务正在进行升级操作

6001

用户中途取消支付操作

6002

网络连接异常

 

5、AlixPay 主要方法描述

  • 方法原型: String  pay(String strInfo);
  • 方法功能: 提供外部商户订单的支付
  • 参数说明: String  strInfo

        主要包含外部商户的订单信息,key="value"形式,以&连接。支付参数示例如下:

partner="2088101568358171"&seller_id="[email protected]"&out_trade_no=
"0819145412-6177"&subject="《暗黑破坏神 3:凯恩之书》"&body="暴雪唯一官方授权
中文版!玩家必藏!附赠暗黑精致手绘地图!绝不仅仅是一本暗黑的故事或画册,而是一个
栩栩如生的游戏再现。是游戏玩家珍藏的首选。
"&total_fee="0.01"&notify_url="http%3A%2F%2Fnotify.msp.hk%2Fnotify.htm"&servic
e
="mobile.securitypay.pay"&payment_type="1"&_input_charset="utf-8"&it_b_pay="30
m"&show_url="m.alipay.com"&sign="lBBK%2F0w5LOajrMrji7DUgEqNjIhQbidR13Gov
A5r3TgIbNqv231yC1NksLdw%2Ba3JnfHXoXuet6XNNHtn7VE%2BeCoRO1O%2BR1
KugLrQEZMtG5jmJIe2pbjm%2F3kb%2FuGkpG%2BwYQYI51%2BhA3YBbvZHVQBY
veBqK%2Bh8mUyb7GM1HxWs9k4%3D"&sign_type="RSA"

 

  • 返回值:本方法调用的结果为字符串格式,形式一般如下:resultStatus={}; result={}

        例如:

resultStatus={9000};memo={};result={partner="2088101568358171"&seller_id="alipa
[email protected]"&out_trade_no="0819145412-6177"&subject="《暗黑破坏神 3:
凯恩之书》"&body="暴雪唯一官方授权中文版!玩家必藏!附赠暗黑精致手绘地图!绝不仅
仅是一本暗黑的故事或画册,而是一个栩栩如生的游戏再现。是游戏玩家珍藏的首选。
"&total_fee="0.01"¬ify_url="http%3A%2F%2Fnotify.msp.hk%2Fnotify.htm"&servic
e="mobile.securitypay.pay"&payment_type="1"&_input_charset="utf-8"&it_b_pay="30
m"&show_url="m.alipay.com"&success="true"&sign_type="RSA"&sign="hkFZr+zE94
99nuqDNLZEF7W75RFFPsly876QuRSeN8WMaUgcdR00IKy5ZyBJ4eldhoJ/2zghqrD
4E2G2mNjs3aE+HCLiBXrPDNdLKCZgSOIqmv46TfPTEqopYfhs+o5fZzXxt34fwdrzN4
mX6S13cr3UwmEV4L3Ffir/02RBVtU="}

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(android)