前言:
最近在做一个独立于中台的聚合支付服务, 来聚合海外的三方支付, 类似于ping++, 中台接入这个聚合支付服务, 使国际区域上的业务接入不再依赖中台做集成。
由于这个聚合服务也相当于一个三方支付SDK, 所以要接入三方服务, 聚合成为类似于ping++这种服务, 我写的也相当于三方聚合服务。
内容:
1.大概流程
2.服务实现
由于接入了某三方,同时聚合服务作为三方可参考ping++的设计 二者对比, 引起了一些思考。
Q1:首先回调鉴权, 某三方服务是使用 平台 secret key hmac 加盐的方式实现,而ping++ 是使用RSA(商户公钥)的形式, 二者的区别是什么?
A1: 区别在于使用RSA验签,可以确认秘钥泄露责任。 secret key 加盐, 平台是有泄露风险的,这样就可以模拟回调造成商户损失, 此时无法确认责任方是平台还是用户自己,而使用rsa就没有这个问题。
Q2: ping++请求鉴权采用rsa + secret 形式, 某三方采用secret key 形式, 有何区别是否有风险
A2: 除了A1的原因, 某三方是无其他风险的, 取决于https可以防范中间人攻击, secret是否明文无所谓
Q3: 如何实现沙盒机制?
A3: 沙盒的设计可以分为支付网关(支付宝, stripe)和基于livekey testkey (ping++)的设计
- 基于key, 三方平台自带沙盒环境 和 生产环境, 订单上分离,可以看成是一个项目两个库,在网关区分写入到哪里。
- 基于支付网关, 可以想象成同一项目,部署两个环境。
作为业务接入方期望在生产调用沙盒环境, 可以配置多个回调(如测试mode 配置商户生产和测试两个环境地址,商户通过标识来判断支付类型), 这也是三方平台使用eventId 的原因(因为每个回调要对应单独的通知状态)。
还有一种简单的方式,直接在创建charge时传入回调地址。
Q4: chargeId, fefundId, eventId 的必要性?
A4: chargeId 为三方关联支付渠道的id, 相当于三方平台唯一订单id, 是必要的。
refundId也是必要的, 因为同一笔charge可以多次退款,所以商户需要对回调是哪一笔退款有感知。像某三方支付,对同一refundId请求两次直接报通用内部错误,没有做幂等处理,商户方是无法感知他生成的这笔退款是否发送成功的,这样是有问题的(场景: 请求返回超时了,但实际成功了)。
eventId除了前面已经谈过的多个回调地址原因, 还有基于回调事件唯一性的考量, 还有通晰平台服务链路, 其实是不必要的。
Q5: charge是否是有状态的?
A5: charge 是有状态的, refund也是有状态的, charge状态的终点可以是success, 而不必是退款(charge 是维护有退款金额的)