首页 > 编程语言 >苹果内购的凭证验证和解密(前端和本地node服务)

苹果内购的凭证验证和解密(前端和本地node服务)

时间:2024-07-01 17:56:08浏览次数:3  
标签:内购 node const 请求 验证 解密 break case message

苹果内购的凭证验证和解密

最近在搞苹果内购,是使用微信提供的Dount提供的小程序转成APP。苹果内购使用的也是他们封装好的js接口,然后后端在解析我传递的支付凭证的时候他一直解析不成功然后我坚信自己的传递参数没有问题,我就自己使用node写了一个本地服务去验证我的支付凭证,所以就有了这个文章。

服务器端代码 (server.mjs)

导入必要模块
import express from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import fetch from 'node-fetch';
  • express: 用于创建一个服务器。
  • bodyParser: 用于解析JSON格式的请求体。
  • cors: 用于解决跨域问题。
  • fetch: 用于发送HTTP请求到Apple的验证服务器。
创建Express应用并配置中间件
const app = express();
const port = 3000;

app.use(cors());
app.use(bodyParser.json());
  • 创建一个Express应用实例。
  • 设置应用端口为3000。
  • 使用cors中间件以允许跨域请求。
  • 使用bodyParser中间件以解析JSON格式的请求体。
定义路由以处理验证请求
app.post('/verifyReceipt', async (req, res) => {
  const { receiptData, password } = req.body;

  try {
    const response = await fetch('https://sandbox.itunes.apple.com/verifyReceipt', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        'receipt-data': receiptData,
        'password': password
      })
    });

    const result = await response.json();
    res.json(result);
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
});
  • 定义一个POST路由/verifyReceipt来处理客户端发送的验证请求。
  • 从请求体中提取receiptDatapassword
  • 使用fetch函数发送POST请求到Apple的沙盒验证服务器https://sandbox.itunes.apple.com/verifyReceipt
  • 请求体包含Base64编码的收据数据和共享密钥。
  • 将Apple返回的结果以JSON格式响应回客户端。
  • 如果请求失败,返回500状态码和错误信息。
启动服务器
app.listen(port, () => {
  console.log(`Server is running on http://localhost:${port}`);
});
  • 启动服务器,并在指定端口上监听连接请求。
  • 要先进行下载这个几个依赖
npm install express body-parser cors node-fetch
  • 然后就是启动这个服务
node server.mjs

前端代码(HTML文件)

基本HTML结构和样式
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>验证苹果内购凭证</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      margin: 0;
      padding: 20px;
      background-color: #f0f0f0;
    }
    .container {
      max-width: 600px;
      margin: 0 auto;
      padding: 20px;
      background-color: white;
      border-radius: 8px;
      box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    }
    .container h1 {
      font-size: 24px;
      margin-bottom: 20px;
    }
    .container textarea {
      width: 100%;
      height: 100px;
      margin-bottom: 20px;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 4px;
      font-family: monospace;
    }
    .container button {
      display: inline-block;
      padding: 10px 20px;
      background-color: #28a745;
      color: white;
      border: none;
      border-radius: 4px;
      cursor: pointer;
      font-size: 16px;
    }
    .container button:disabled {
      background-color: #ccc;
    }
    .container .result {
      margin-top: 20px;
      white-space: pre-wrap;
      word-wrap: break-word;
      background-color: #f8f9fa;
      padding: 10px;
      border: 1px solid #ccc;
      border-radius: 4px;
      font-family: monospace;
    }
  </style>
</head>
<body>
  <div class="container">
    <h1>粘贴你的内购凭证(transactionReceipt)</h1>
    <textarea id="receiptData" placeholder="粘贴你的内购凭证(transactionReceipt)"></textarea>
    <button id="verifyButton" onclick="verifyReceipt()">解析凭证</button>
    <div id="result" class="result"></div>
  </div>
  • 设置HTML文档的基本结构和样式,确保页面看起来整洁美观。
JavaScript代码
  <script>
    async function verifyReceipt() {
      const receiptData = document.getElementById('receiptData').value;
      const resultElement = document.getElementById('result');
      const verifyButton = document.getElementById('verifyButton');
      
      if (!receiptData) {
        resultElement.textContent = '请输入base64编码的收据数据';
        return;
      }

      verifyButton.disabled = true;
      resultElement.textContent = '解析中...';

      try {
        const response = await fetch('http://localhost:3000/verifyReceipt', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify({
            'receiptData': receiptData,
            'password': 'your-shared-secret' // 替换你的秘钥可有可无
          })
        });

        const result = await response.json();
        handleReceiptResult(result, resultElement);
      } catch (error) {
        resultElement.textContent = `Error: ${error.message}`;
      }

      verifyButton.disabled = false;
    }

    function handleReceiptResult(result, resultElement) {
      const status = result.status;
      let message;

      switch (status) {
        case 0:
          message = '验证成功!';
          break;
        case 21000:
          message = 'App Store无法读取你提供的JSON对象。';
          break;
        case 21002:
          message = '收到的数据无效。';
          break;
        case 21003:
          message = '收据无法被验证。';
          break;
        case 21004:
          message = '你提供的共享密钥与帐户文件中的共享密钥不匹配。';
          break;
        case 21005:
          message = '收据服务器当前不可用。';
          break;
        case 21006:
          message = '收据有效,但订阅已过期。';
          break;
        case 21007:
          message = '此收据来自测试环境,但已发送到生产环境进行验证。';
          break;
        case 21008:
          message = '此收据来自生产环境,但已发送到测试环境进行验证。';
          break;
        case 21010:
          message = '收据无效,无法被验证。';
          break;
        default:
          message = `未知错误,状态码:${status}`;
      }

      resultElement.textContent = `结果: ${JSON.stringify(result, null, 2)}\n\n信息: ${message}`;
    }
  </script>
</body>
</html>
  • verifyReceipt函数:当用户点击“解析凭证”按钮时,获取输入的收据数据,并发送POST请求到本地代理服务器(http://localhost:3000/verifyReceipt)。显示解析结果或错误信息。
  • handleReceiptResult函数:处理Apple返回的验证结果,根据状态码显示具体的错误消息。
    • 根据Apple内购验证API的状态码显示相应的信息,例如状态码0表示验证成功,状态码21000表示App Store无法读取你提供的JSON对象,等等。

作用

  • 服务器端代码

    • 接收客户端发送的请求,并将请求转发到Apple的验证服务器。
    • 处理Apple返回的结果,并将结果返回给客户端。
    • 通过设置CORS和解析JSON请求体,确保请求和响应的正确处理。
  • 前端代码

    • 提供用户界面,允许用户输入Base64编码的内购凭证。
    • 将用户输入的凭证发送到本地服务器进行验证。
    • 处理服务器返回的结果,并在页面上显示详细的验证结果和错误信息。

通过这种方式,用户可以方便地验证Apple内购凭证,并获取详细的验证结果和错误信息。这样可以帮助开发人员和用户了解验证过程中可能出现的问题,并采取相应的措施进行处理。

标签:内购,node,const,请求,验证,解密,break,case,message
From: https://blog.csdn.net/2301_80817413/article/details/140043494

相关文章

  • uni-app编译错误:“hasInjectionContext“ is not exported by “node_modules/.pnpm/p
    1.问题背景当我们接手一个新的uni-app项目(最头疼了x_x),可能会想到删掉node_modules和pnpm-lock.yaml后,执行npminstall或npminstall重新安装依赖包,然后执行pnpmdev:mp-weixin编译,但可能会遇到如下错误:"hasInjectionContext"isnotexportedby"node_modul......
  • Java Chassis 3技术解密,流式响应如何简化AI应用开发
    本文分享自华为云社区《JavaChassis3技术解密:流式响应和人工智能应用开发》,作者:liubao68。随着生成式人工智能技术的发展,应用程序开发者对于流式响应(StreamingResponses)的诉求越来越多。服务器事件推送(ServerPushEvents)技术能够在使用HTTP协议的前提下,提供流式响应能力......
  • Electron | throw new Error('Electron failed to install correctly, please delete
    https://github.com/electron-vite问题原因在install的时候node_modules/electron/中的文件丢失造成程序无法执行解决方案要重新安装加载electron。这只是其中一个解决方案。参考https://github.com/pangxieju/electron-fix//1.npminstal//2.npminstall-gelectron......
  • Node.js与ES632_Node.js入门
    一、什么是Node.js简单的说Node.js就是运行在服务端的JavaScript。Node.js是一个基于ChromeJavaScript运行时建立的一个平台。Node.js是一个事件驱动I/O服务端JavaScript环境,基于Google的V8引擎,V8引擎执行Javascript的速度非常快,性能非常好。二、Node.js安装1、下......
  • nodejs 统计算指定后缀,格式的文件
    都是gpt生成的 可用版本constfs=require('fs');constpath=require('path');functioncountHtmlFiles(dirPath){letcount=0;constfiles=fs.readdirSync(dirPath);files.forEach(file=>{constfilePath=path.join(dirPath,......
  • 使用fnm安装node,并自定义安装路径
    作者:咕魂时间:2024年6月23日本教程使用winget对fnm进行安装,主要分两部分,第一步安装fnm,第二步安装nodejs其中nodejs配置成功后只在powershell中生效1.fnm的安装假设我们自定义安装路径为:D:\fnm下载安装fnmwingetinstallSchniz.fnm--locationD:\fnm由于要从github上下......
  • 深入探索YARN集群:NodeManager内存配置与管理全攻略
    深入探索YARN集群:NodeManager内存配置与管理全攻略引言ApacheHadoopYARN(YetAnotherResourceNegotiator)作为Hadoop生态系统中的一个关键组件,为集群资源管理和作业调度提供了强大的支持。在YARN集群中,NodeManager(NM)扮演着资源管理和任务执行的重要角色。本文将深入探讨......
  • inode and vnode
    文件系统格式windows:FAT,NTFS;Linux:ext,ext1/2/3/4,xfs;网络:NFS,SMB(sambaSMB/CIFS)云:VFS:Linux&MacOS在文件系统之上虚拟出一层文件系统,VirtualFS;POSIX:portableoperatingsysterminterfaceofUnix.来自用户进程的调用都通过POSIX系统调用(open,read,wr......
  • [本科项目实训] Node.js、npm、pnpm配置及GLIBC_2.28缺失解决方案
    问题描述Node.js是一个基于Google的V8引擎的事件驱动I/O服务端JavaScript环境。以下主要解决在Ubuntu环境中的Node配置问题。解决方案使用node-v可以查看当前的node版本,如果未安装node和npm可以尝试以下指令:aptupdateaptupgradeapt-getinstallnodejsapt-get......
  • [nodejs]package.json里的依赖版本
    依赖分类依赖根据开发环境需要和实际运行环境需要,分为dependencies和devDependencies。例如:typescript和eslint属于devDependencies,而vue和axios等属于dependencies。版本号组成版本由两部分组成,一是前面的前缀符号,二是版本号。这里先介绍版本号。版本号版本号的形式是:a.b......