You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用Apple API验证交易时如何规避401错误?

Apple API验证交易时如何规避401错误?

我之前在Node.js后端对接StoreKit 2的交易验证时,也踩过一模一样的401认证失败的坑,折腾了好半天才把问题都排查干净,给你分享几个亲测有效的排查和解决方向:

  • 先把P8密钥的“基础检查”做扎实
    别小看这个,我当初就是因为下载P8的时候不小心多复制了一个空行,导致密钥格式错误。你要确认:

    • P8文件是从Apple开发者后台直接下载的,没有手动修改过内容,开头的-----BEGIN PRIVATE KEY-----和结尾的-----END PRIVATE KEY-----必须完整,中间的密钥部分每行是64个字符,不能有多余的空格、换行或者乱码。
    • 你的loadKeyFromP8File读取后,打印出来的密钥内容要和原文件完全一致,避免读取时的编码问题(虽然你用了utf8,但最好核对一遍)。
  • JWT的参数必须完全贴合Apple的“死要求”
    Apple对JWT的字段校验特别严格,差一点都不行:

    • iss:必须是你开发者账号的Team ID(10字符的那个,在会员中心能找到),别把Bundle ID或者其他ID混进来。
    • iat:签发时间要用服务器的Unix时间戳,别用客户端传的时间,服务器时间最好同步下NTP,避免时间差导致校验失败。
    • exp:过期时间最多只能是签发后180天,不能设得更长,比如iat + 86400*180就刚好。
    • aud:沙箱环境填appstoreconnect-v1-sandbox,生产环境填appstoreconnect-v1,我之前就是沙箱测试用了生产的aud,直接401。
    • kid:是你P8密钥对应的密钥ID,创建密钥的时候Apple会显示这个ID,必须和当前P8文件一一对应,不能用其他密钥的kid。
  • 签名算法绝对不能错
    Apple只认ES256(ECDSA with P-256 and SHA-256)算法,用错直接401。比如用jose库的话,签名时要明确指定算法;如果用jsonwebtoken,记得要安装elliptic依赖,然后在签名选项里写algorithm: 'ES256',别用默认的HS256。
    给你贴一段我现在在用的简化版代码参考:

    const { SignJWT } = require('jose');
    const fs = require('fs');
    const { importPKCS8 } = require('jose/webcrypto/pkcs8');
    
    async function generateAppleJWT() {
      const privateKey = fs.readFileSync('./SomeKey.p8', 'utf8');
      const teamId = '你的Team ID';
      const keyId = '你的密钥ID';
      const isSandbox = true; // 测试时设为true,生产改false
      const aud = isSandbox ? 'appstoreconnect-v1-sandbox' : 'appstoreconnect-v1';
    
      return await new SignJWT({})
        .setProtectedHeader({ alg: 'ES256', kid: keyId })
        .setIssuer(teamId)
        .setIssuedAt()
        .setExpirationTime('180d')
        .setAudience(aud)
        .sign(await importPKCS8(privateKey, 'ES256'));
    }
    
  • API端点和环境要配对
    沙箱测试一定要用沙箱的API地址:https://api.storekit.itunes.apple.com/inApps/v1/transactions/{transactionId},生产环境用https://buy.itunes.apple.com/inApps/v1/transactions/{transactionId},把沙箱的JWT用到生产端点,或者反过来,肯定会401。

  • 最后检查P8密钥的权限
    创建P8密钥的时候,必须勾选In-App Purchase的权限!我之前创建密钥的时候漏了这个选项,导致密钥没有访问交易验证API的权限,哪怕JWT生成对了,Apple还是直接返回401。去开发者后台的密钥页面,找到对应的P8密钥,确认它的权限里包含In-App Purchase。

备注:内容来源于stack exchange,提问作者Jedi Exile

火山引擎 最新活动