Apple pay 服务端

2023-04-08 ⏳1.3分钟(0.5千字)

本文介绍 Apple 支付在服务端的处理.

支付流程

注意文中服务端指业务方/商家的服务端,而苹果的服务端叫 App Store Server。

  1. 客户端支付成功会保留支付凭据同时通知到 App Store Server
  2. 客户端上传凭据到服务端
    1. 这里拿到凭据可以关联用户信息
    2. 主动验证支付信息
  3. App Store Server 通过 URL 回调
  4. 服务端拿到支付信息并验证回调有效性
  5. 服务端发放权益
通信流程

在服务端处理 Apple 支付需要实现一个回调 URL,这个 URL 由 Apple 服务器向其发出的通知请求时调用。可以使用此 URL 来验证收据、获取有关购买的其他信息。回调配置方法

验证票据方案选取

官方 提供了客户端和服务端不同的验证方式 ,如下:

Capability On-device validation Server-side validation
Validates authenticity of receipt Yes Yes
Includes subscription renewal transactions Yes Yes
Includes additional subscription information No Yes
Resistant to device clock change No Yes

这里我们介绍服务端的验证。

获取票据

首先去苹果查询支付凭据自然需要客户端先上传支付凭据

/* Load the receipt from the app bundle. */
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];

if (!receipt) { 
    NSLog(@"no receipt");
    /* No local receipt -- handle the error. */ 
} else {
    /* Get the receipt in encoded format. */
    NSString *encodedReceipt = [receipt base64EncodedStringWithOptions:0];
}

/* ... Send the receipt data to your server ... */

验证票据

这里可以查询到相关的请求信息和响应信息。

注意这里沙盒环境跟生产验证的 URL 不一致

// 这里仅展示必要的字段
{
  "receipt-data": "", // 注意这里是 base64 后的支付凭据
  "password": "" // 共享密钥
}

共享密钥的获取地址: https://appstoreconnect.apple.com/access/shared-secret

验证 App Store Server 回调

Api 详情,我们发现响应体里只有一个字段

{
  "signedPayload": "" // "The payload in JSON Web Signature (JWS) format, signed by the App Store."
}

这里有个问题, 我们怎么验证苹果的回调请求是合法的,而不是别人伪造的呢?

JWT

苹果使用了 JWT 。(Calls to the API require JSON Web Tokens (JWTs) for authorization)

Header Field Value
alg - Encryption Algorithm ES256
All JWTs for App Store Connect API must be signed with ES256 encryption.
kid - Key Identifier Your private key ID from App Store Connect; for example 2X9R4HXF34.
typ - Token Type JWT

具体的实现细节可以参考 Apple 的官方文档: App Store Server Notifications API

然后我们发现 Apple 返回的 jwt header 里有以下字段:

{
  "alg": "ES256",
  "x5c": [
    "MIIEMDCC...",
    "MIIDFjCCApygAw...",
    "MIICQzCCAcmgAw..."
  ]
}

可以看到 jwt 算法用的是 ES256 那么 x5c 又是什么呢?

X5C

x5c 是 JWT 头(header)中的一个字段,它是一个公钥证书链数组,用于验证 JWT 签名,x5c 具体可以看这里。需要根据 rfc5280 进行验证。

具体验证

这里我们需要从第一个证书验证 JWT 是否被篡改,

  1. 如果第一个证书是伪造的呢?
    1. 用第二个证书验证第一个
  2. 如果第二个也是伪造的呢?
    1. 一次用下一个如此反复
  3. 如果都是伪造的呢?
    1. 最后一个需要 Apple 根证书去验证 下载链接

验证结束我们就可以根据响应来处理具体业务需求了, 字段对应的意义可以从 依据官方文档处理, 包含了订阅付费信息等。

TODO:

参考代码

其他细节

参考致谢:

  1. https://juejin.cn/post/7039970403770433544
  2. WWDC