Google 支付方案设计
接入支付前期准备
主要是准备好Google开发者账号,创建项目,授权,获取密钥,创建商品等等。。。
前提说明
GooglePay 分为 Subscriptions (订阅) 和 In-App Purchases (内购)
官方文档在这里
In-App Purchases 内购
客户端代码流程(网上)
支付流程
- 向用户展示他们可以购买什么。
- 启动购买流程,以便用户接受购买交易。
- 在您的服务器上验证购买交易。
- 向用户提供内容。
- 确认内容已传送给用户。对于消耗型商品,请将购买的商品标记为消耗,以便用户能够再次购买商品。
服务端验证订单流程
- 接收客户端传递来的参数
- 根据客户端参数的订单ID(第三方订单ID)去库里查询是否存在订单
- 如果存在订单,检查订单状态,如果不是初始化状态,说明订单已经被处理过了,如果是初始化状态,则走步骤 5
- 如果不存在订单则创建订单
- 服务端调用 Google API 校验订单状态
- 如果链接不上 Google 服务器或者开启了本地校验
- 服务端本地 RSA 签名校验订单状态
- 订单校验失败,告知客户端,修改订单状态,记录订单失败信息
- 订单校验成功,更改订单状态,记录订单信息
- 发送 Kafka 消息,告知客户端处理成功
注意事项,校验订单时需要加分布式锁(按照订单号为锁),避免客户端多次重试出现并发问题
服务端校验订单方式
服务端校验订单,主要是校验订单的状态,可以分为两种验证方式:
- 服务端RAS签名验证
- 服务端调用Google API 验证
可以两种方式都做,原因是:
- Google api 方式需要连接Google服务器,如果谷歌服务器连接失败,此时可以退而求其次,使用本地签名验证
- 服务端RAS签名验证有一些风险,据说有些模拟器可以伪造数据
服务端签名验证
客户端返回参数大致情况:
signtureData:
{
"orderId": "1111111111.111111111111",
"packageName": "com.abc.item",
"productId": "com.abc.item.1",
"purchaseTime": 1423197856877,
"purchaseState": 0,
"purchaseToken": "dccfjnioeeojanngnfspekea.AO-J1OzsBdFJhqhLtvtybnQbBMxELYL4M-wClITbJFd-rpnPzYWCOlHyK69xgXBYN8lx99XfMBhD8JPg6u3SsgNvPt2hhbvogszRxjtA15rP-qWBYv_Rytw"
}
signture:XCtoXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXy2Nyp047DV0f1VZ39CV7dCmLXouSFrYBxoS7NAVejgmHU+WXLLI61M4GjRrBMtEuW2HnUye8hfbsjlGfqI+MZDqAbfAi+3i6fPwIOwDS+tdAAU+VUz3cDyBubJhL+tZIa1uT6H0ifHN0KXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX7xpsZTctzf09XGKdqNktrFbNm4pqHqDttEg98xmiP/oKyitZpLoNyvrk7nEXxUstGJhKejPt9wyn3il+s7cT3TD4xyEznxeBuD+zVa/sCXAZw==
复制代码
服务端校验: publicKey , 谷歌后台提供
//result=true的话就成功了
boolean result = RSASignature.doCheck(signtureData, signture, publicKey);
复制代码
服务端调用Google API 验证订单状态
Google并未像Apple那样提供一个接口来校验订单的信息,但是提供了一个获取订单状态的接口,可以通过这个接口在GooglePlay服务器获取某个订单,查看其状态是否合法达到校验目的
服务端调用Google API验证订单也有两种方式:
- 一种是借助 Google SDK方式
- 另一种是使用Http请求,但是需要自己维护请求API时需要的 refreshToken、access_token(Auth2流程),个人感觉比较麻烦
建议使用 Google SDK接入方式
参考:www.cnblogs.com/kevin-zou/p…
支付表结构设计
- 商品表
CREATE TABLE `goods` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`goods_code` varchar(20) NOT NULL COMMENT '商品code',
`goods_name` varchar(20) NOT NULL COMMENT '商品名称',
`type` tinyint(1) DEFAULT NULL COMMENT '虚拟币类型',
`quantity` int(11) DEFAULT NULL COMMENT '数量',
`price` bigint(20) NOT NULL DEFAULT 0 COMMENT '售价',
`pay_channel` tinyint(1) DEFAULT NULL COMMENT '支付渠道:0 GooglePay 1 ApplePay 2 PayPal',
`distribution_channel` varchar(200) NOT NULL COMMENT '分销渠道,多个逗号隔开',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `index_goods_code` (`goods_code`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;
复制代码
- 支付渠道表
CREATE TABLE `pay_channel` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`channel_name` varchar(20) DEFAULT NULL COMMENT '渠道名称',
`link` varchar(100) DEFAULT NULL COMMENT '链接 H5类型下使用',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;
复制代码
- 订单表
CREATE TABLE `order` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`order_sn` varchar(20) NOT NULL COMMENT '订单编号',
`third_order_sn` varchar(20) NOT NULL COMMENT '第三方订单编号',
`origin_order_sn` varchar(20) NOT NULL COMMENT '源订单号,发起退款时关联的订单',
`user_id` bigint(20) DEFAULT NULL COMMENT '用户ID',
`type` tinyint(1) NOT NULL COMMENT '订单类型 0 付款订单 1 退款订单',
`goods_code` varchar(20) NOT NULL COMMENT '商品code',
`price` bigint(20) NOT NULL DEFAULT 0 COMMENT '订单金额',
`payment_method` tinyint(1) DEFAULT NULL COMMENT '付款方式:0 Google pay ',
`status` tinyint(1) DEFAULT NULL COMMENT '订单状态:0:初始化 1:已完成 2 已经取消 3 已退款',
`deliver_status` tinyint(1) DEFAULT NULL COMMENT '发货状态:0:发货失败 1:发货成功',
`complete_time` datetime DEFAULT NULL COMMENT '订单完成时间',
`refund_time` datetime DEFAULT NULL COMMENT '退款时间',
`device` tinyint(1) DEFAULT NULL COMMENT '设备:0:IOS 1:安卓',
`origin_info` varchar(500) DEFAULT NULL COMMENT '第三方支付信息',
`remark` varchar(200) DEFAULT NULL COMMENT '备注',
`refund_reason` varchar(200) DEFAULT NULL COMMENT '退款原因',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`),
KEY `index_order_sn` (`order_sn`) USING BTREE,
KEY `index_third_order_sn` (`third_order_sn`) USING BTREE
KEY `index_user_id` (`third_order_sn`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4;
复制代码
微服务设计
新加一个 order 服务? 现在有一个 ironman-service-commodity 服务,支付商品可以放这里