feat(支付): 新增Apple IAP支付支持
Build docker and publish / build (20.15.1) (push) Has been cancelled

实现Apple应用内购支付功能,包括:
1. 新增AppleIAP和ApplePay支付平台枚举
2. 添加IAP验证接口/v1/public/iap/verify处理初购验证
3. 实现Apple服务器通知处理逻辑/v1/iap/notifications
4. 新增JWS验签和JWKS公钥缓存功能
5. 复用现有订单系统处理IAP支付订单

相关文档已更新,包含接入方案和实现细节
This commit is contained in:
2025-12-09 00:53:25 -08:00
parent 4b6fcb338e
commit d95911d6bd
15 changed files with 654 additions and 34 deletions
@@ -0,0 +1,47 @@
## 实施目标
- 复用现有订单与队列赋权,接入 Apple 自动续期(IAP),保持报表/审计/通知一致。
## 方案选择
- 采用“平台化复用 + 合成订单”的方式:Apple 由客户端结算 + 服务器通知驱动,服务端生成“已支付订单”进入现有赋权与续费流程。
## 具体改动(按文件)
1) 平台标识
- 更新 `pkg/payment/platform.go`:新增 `AppleIAP` 枚举与名称(仅标识,不参与 `PurchaseCheckout`)。
2) 路由与 Handler
- 新增公共接口:`POST /v1/public/iap/verify`
- 位置:`internal/handler/public/iap/verifyHandler.go`
- 逻辑:调用 `internal/logic/public/iap/verifyLogic.go`,以 `originalTransactionId` 验证 Apple 购买,生成“已支付订阅订单”,入队激活。
- 新增通知接口:`POST /v1/iap/notifications`
- 位置:`internal/handler/notify/appleIAPNotifyHandler.go`
- 逻辑:调用 `internal/logic/notify/appleIAPNotifyLogic.go`,JWS 验签后按事件(初购/续期/退款)生成或更新订单,触发续费或撤销权益。
- 路由注册:
- `internal/handler/routes.go` 增加 `/v1/public/iap/verify` 路由。
- `internal/handler/notify.go` 增加独立 `/v1/iap/notifications` 路由(Apple 不带 `:token`)。
3) 数据与模型
- 在用户订阅(或新建 `iap_binding` 表)绑定:`originalTransactionId``environment``latestExpiresDate`
- 订单字段复用:`Method=AppleIAP``TradeNo=originalTransactionId``Type=1/2`(订阅/续费),`Status=2`(已支付),金额可取通知中的价格;取不到则置 `Amount=0` 保证流程。
4) 逻辑复用与改造点
- 赋权:复用 `queue/logic/order/activateOrderLogic.go:165 NewPurchase`
- 续费:复用 `queue/logic/order/activateOrderLogic.go:529 updateSubscriptionForRenewal`
- 不改动 `internal/logic/public/portal/purchaseCheckoutLogic.go` 的渠道路由(Apple 不走此流程)。
5) 安全与幂等
- Apple JWS 验签:拉取并缓存 JWKS 公钥,校验通知;拒绝无效签名。
- 幂等:以 `notificationId`/`transactionId``originalTransactionId` 去重处理。
6) 客户端协作
- iOS:完成 StoreKit 购买后携带 `originalTransactionId` 调用 `/v1/public/iap/verify`
- 续费:依赖 Server Notifications v2 自动驱动,无需客户端调用。
7) 测试与监控
- 沙盒验证初购、续期、重试与宽限期、退款撤销;注意元数据延迟(~1小时)。
- 指标:通知验签失败、API 调用失败、幂等冲突、状态不一致报警。
## 交付节奏
- 第一步:平台枚举与路由骨架;
- 第二步:`verify` 验证与“合成订单”生成;
- 第三步:通知验签与事件映射;
- 第四步:沙盒联调,确认队列赋权与续费延长。
@@ -0,0 +1,92 @@
## 结论
* 可以复用你现有的“订单→支付成功→订单激活(赋权)→通知/返佣”的主干流程,但“支付环节”不能复用第三方网关逻辑,必须改为 Apple IAP 的校验与事件驱动。
* 复用范围:订单模型、续费与赋权队列、优惠/手续费计算、通知与返佣;差异点:支付下单与回调换成“StoreKit 客户端购买 + 服务端向 Apple 校验 + Apple Server Notifications v2”。
## 可复用的部分
1. 订单激活与赋权
* 新购赋权:`queue/logic/order/activateOrderLogic.go:164-193``NewPurchase`
* 续费赋权:`queue/logic/order/activateOrderLogic.go:473-515``Renewal`
* 流量重置与充值:`queue/logic/order/activateOrderLogic.go:564-626`, `630-675`
1. 订单与费用模型
* 订单结构:`internal/model/order/order.go:5-29` 可继续承载 IAP 订单(新增字段映射 Apple 交易)
* 费用/折扣/礼金计算逻辑保持不变
1. 队列驱动
* 仍使用“支付成功→入队→处理”的模式:`queue/logic/order/activateOrderLogic.go:65-86`
## 必须独立实现的部分
1. Apple IAP 支付与校验
* 客户端使用 StoreKit 购买,拿到 `originalTransactionId`
* 服务端调用 App Store Server API,基于 `originalTransactionId` 校验订阅有效性并取交易历史
1. Apple Server Notifications v2
* 在 App Store Connect 配置通知 URL
* 服务端实现 JWS 验签,解析事件并落库:续期、失败、宽限期、退款、撤销等
## 整合方式(复用策略)
1. 引入平台枚举“AppleIAP”
*`pkg/payment/platform.go` 增加 `AppleIAP`,用于平台标识与管理端展示
1. 订单创建策略(两种)
* 方案 A(推荐):用户在 iOS 内购完成后由客户端上报 `originalTransactionId`,服务端校验通过后“合成一个已支付订单”(`status=2`),触发既有赋权队列
* 方案 B:也可预建“待支付订单”,但 `PurchaseCheckout` 不走网关,只返回“client\_iap”类型,提示客户端用 StoreKit;支付完成后再校验并更新为 `Paid` 入队
1. 状态与权益判定
* 服务端统一以 Apple 校验与通知为准,抽象为 `active/in_grace_period/in_billing_retry/expired/revoked` 并映射到你的订阅与订单状态
## 服务端接口与流程
* `POST /apple/iap/verify`:入参 `originalTransactionId`,校验并创建/更新订单与用户订阅,返回当前权益
* `POST /apple/iap/notifications`:接收 Apple JWS 通知,验签后更新订阅与订单状态(幂等)
* `GET /subscriptions/me`:面向客户端查询当前订阅与权益(聚合 Apple 校验结果)
## 数据模型映射
* 在订单/订阅表补充字段(建议):`Provider=apple_iap``OriginalTransactionId``Environment``ExpiresDate``AutoRenewStatus``InGracePeriod``LastEventType`
* 产品映射:`productIdApp Store ↔ internal subscribeId`,保证同一权益统一计费
## 回调与安全
* JWS 验签:缓存 Apple JWKS 公钥、短生命周期缓存
* App Store Server API:使用 App Store Connect API KeyES256)发起请求,区分生产/沙盒
* 幂等:按 `notificationId/transactionId` 去重
## 测试与上线
* 沙盒测试:购买、续期、失败、宽限期、退款全链路;注意沙盒元数据生效可能需 \~1 小时
* 监控:通知处理失败、验签失败、API 调用异常报警
## 交付物(最小实现)
1. 平台枚举新增 `AppleIAP`
2. `POST /apple/iap/verify``POST /apple/iap/notifications` 路由与逻辑骨架
3. App Store Server API 客户端封装(校验、交易历史、订阅状态)
4. 订单合成与入队赋权打通(复用 `OrderStatusPaid``ProcessTask`
5. 数据表字段扩展与迁移脚本