苹果商店退款API PHP验签 signedPayload

2022-11-04  本文已影响0人  belm
  1. 苹果商店后台配置服务端退款和订阅通知接受地址
    打开 https://appstoreconnect.apple.com/apps 进入到对应的APP
    综合=》App信息 ,可分别配置正式和沙盒接受地址
    image.png
    参考地址 https://help.apple.com/app-store-connect/#/dev0067a330b

2.目前苹果此通知API已经更新到第2个版本, 此版本使用JWT签名,需要我们验签后使用,通知数据格式如下:

{"signedPayload":"xxxxxx"}

可以将签名内容复制到https://jwt.io/ 是验签ok的,后面就想办法用PHP验签
jwt官网显示header部分如下

{
  "alg": "ES256",
  "x5c": ['key1', 'key2', 'key3']
}

alg是加密算法,x5c是一种协议标准,可参考定义https://www.rfc-editor.org/rfc/rfc7515
x5c里面的3个key, 第1个公钥是用来验证payload里面的值是否合法的,第3个公钥是用来跟苹果的root证书比对是否一致 https://www.apple.com/certificateauthority/
下载https://www.apple.com/certificateauthority/AppleRootCA-G3.cer

openssl x509 -inform der -in AppleRootCA-G3.cer -out AppleRootCA-G3.pem

得出来pem的值应该跟x5c里面的第3个一样。
php引用jwt库

"firebase/php-jwt": "^5.2",
    public static function decodePayNotifyV2($jwt)
    {
        list($header, $payload, $sign) = explode('.', $jwt);
        $header_decode = base64_decode($header);
        $header_json =json_encode($header_decode);

        if (!isset($header_json['x5c'])) {
            return false;
        }
        
       //这一步是将公钥转成对应的格式
        $pubkey = createPublicKey($header_json['x5c'][0], 'BEGIN CERTIFICATE', 'END CERTIFICATE');
        try {
            $decoded = JWT::decode($jwt, $pubkey, array($header_json['alg']));
        } catch (UnexpectedValueException $e) {
            return false;
        }
        return get_object_vars($decoded);
    }
        $payload_json = Apple::decodePayNotifyV2($data['signedPayload']);

        if (empty($payload_json) || !isset($payload_json['data'])) {
            return;
        }

        $payload_json['data'] = get_object_vars($payload_json['data']);
        $t_payload_json = Apple::decodePayNotifyV2($payload_json['data']['signedTransactionInfo']);

        if (empty($t_payload_json) || empty($t_payload_json['transactionId'])) {
            return;
        }

        $vals = $t_payload_json;

        $vals['appid'] = $appid;
        $vals['notificationType'] = $payload_json['notificationType'];
        $vals['notificationUUID'] = $payload_json['notificationUUID'];
        $vals['appAppleId'] = $payload_json['data']['appAppleId'];
        $vals['bundleVersion'] = $payload_json['data']['bundleVersion'];
        $vals['version'] = $payload_json['version'];

        $vals['purchaseDate'] = date('Y-m-d H:i:s', substr($vals['purchaseDate'], 0, 10));
        $vals['originalPurchaseDate'] = date('Y-m-d H:i:s', substr($vals['originalPurchaseDate'], 0, 10));
        $vals['signedDate'] = date('Y-m-d H:i:s', substr($vals['signedDate'], 0, 10));

        if (isset($vals['revocationDate'])) {
            $vals['revocationDate'] = date('Y-m-d H:i:s', substr($vals['revocationDate'], 0, 10));
        }

遇到的问题
1.刚开始生成公钥,使用的是

-----BEGIN PUBLIC KEY-----
xxxxx
-----END PUBLIC KEY-----

一直验签不通过,后面改成下面这样就正常了,猜想这是x5c规范?

-----BEGIN CERTIFICATE-----
xxxxx
-----END CERTIFICATE-----

2.x5c里面的第一个是用来验签的key
3.参考文档
https://cloud.tencent.com/developer/article/1939304

上一篇下一篇

猜你喜欢

热点阅读