applepay和常规国内的支付流程完全不一样,理解起来很复杂,我做完后有了一个理解:

首先在app管理在苹果网站上架一个产品,有对应的id和价格,名称等

1.客户在苹果前端购买完产品后会返回一个购买凭证信息,{"receipt-data" : "MIIT9wYJKoZIhvcNAQcCoIIT6DCCE……"},大概有8000+的长度,发送到客户端;

2.本地存储购买凭证后可根据需要生成业务订单号等信息;

3.将购买凭证、业务订单号等信息传至服务端进行购买校验;

4.Java服务端做的工作在这个地方,因为我这边会在成功后存在服务端数据库所以先做了校验是否是重复消费,没有重复消费后将购买凭证信息发送到苹果商店验证是否有效;

5.根据返回的结果判断是否成功,并进行业务处理;

0 正常
21000 App Store不能读取你提供的JSON对象
21002 receipt-data域的数据有问题
21003 receipt无法通过验证
21004 提供的shared secret不匹配你账号中的shared secret
21005 receipt服务器当前不可用
21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送
21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务
21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务

6.返回客户端


下面是Java服务端的代码,只有一个对外的购买凭证校验接口

/*** 苹果支付回调验证* 0 正常* 21000 App Store不能读取你提供的JSON对象* 21002 receipt-data域的数据有问题* 21003 receipt无法通过验证* 21004 提供的shared secret不匹配你账号中的shared secret* 21005 receipt服务器当前不可用* 21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送* 21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务* 21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务* transactionId 单号* receipt前端返回信息* type 线上/开发环境用不同的请求链接(0:沙盒 1:线上)*/@PostMapping("/applePay/verify")@ResponseBodypublic String applePayVerify(@RequestBody @Valid String transactionId, String receiptDate,Integer type) throws Exception {log.info("苹果支付回调验证param:{}", JSONObject.toJSONString(transactionId));try {//1.本地验证是否有重复订单号List<PayOrderInfo> payOrderInfoList = tradeServiceForDb.getPayListByChannelTradeNo(transactionId);if (CollectionUtils.isNotEmpty(payOrderInfoList)) {log.info("此苹果订单号已存在对应支付成功订单,transactionId:{}", transactionId);return dataJson("此苹果订单号已存在对应支付成功订单").toJSONString();}//2.先线上测试    发送平台验证String verifyResult = ApplePayUtil.buyAppVerify(receiptDate, applePayType);// 苹果服务器没有返回验证结果if (verifyResult == null) {log.error("苹果服务器无此订单信息,transactionId:{}", transactionId);return errorJson("苹果服务器无此订单信息").toJSONString();} else {// 苹果验证有返回结果log.info("苹果平台返回JSON:" + verifyResult);JSONObject jsonObject = JSONObject.parseObject(verifyResult);String states = jsonObject.getString("status");if ("21007".equals(states)) {//2.在沙盒测试  发送平台验证verifyResult = ApplePayUtil.buyAppVerify(type, applePayType);log.info("沙盒环境,苹果平台返回JSON:" + verifyResult);jsonObject = JSONObject.parseObject(verifyResult);states = jsonObject.getString("status");return dataJson("沙盒环境,状态为:" + states).toJSONString();}log.info("苹果平台返回值param:{}" + jsonObject);// 前端所提供的收据是有效的    验证成功if (states.equals("0")) {String r_receipt = jsonObject.getString("receipt");JSONObject returnJson = JSONObject.parseObject(r_receipt);String in_app = returnJson.getString("in_app");JSONObject in_appJson = JSONObject.parseObject(in_app.substring(1, in_app.length() - 1));String product_id = in_appJson.getString("product_id");// 订单号String transaction_id = in_appJson.getString("transaction_id");//下面是具体的业务代码,根据需要,我这边将订单存入了数据库去判断是否是重复消费//----------------------------------------------------------------------return errorJson("苹果服务器验证单号或产品类型不一致").toJSONString();} else {log.error("苹果服务器验证receipt数据有问题,data:{}", receiptDate);return errorJson("苹果服务器验证receipt数据有问题").toJSONString();}}} catch (Exception e) {log.error("苹果验证服务异常", e);return errorJson("苹果服务异常").toString();}}

下面是发送苹果服务器校验具体工具类

public class ApplePayUtil {private static class TrustAnyTrustManager implements X509TrustManager {@Overridepublic void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}@Overridepublic X509Certificate[] getAcceptedIssuers() {return new X509Certificate[]{};}}private static class TrustAnyHostnameVerifier implements HostnameVerifier {@Overridepublic boolean verify(String hostname, SSLSession session) {return true;}}private static final String url_sandbox = "https://sandbox.itunes.apple.com/verifyReceipt";private static final String url_verify = "https://buy.itunes.apple.com/verifyReceipt";/*** 苹果服务器验证** @param receipt 账单* @return null 或返回结果 沙盒 https://sandbox.itunes.apple.com/verifyReceipt* @url 要验证的地址*/public static String buyAppVerify(String receipt, int type) throws Exception {//环境判断 线上/开发环境用不同的请求链接String url = "";if (type == 0) {url = url_sandbox; //沙盒测试} else {url = url_verify; //线上测试}SSLContext sc = SSLContext.getInstance("SSL");sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());URL console = new URL(url);HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();conn.setSSLSocketFactory(sc.getSocketFactory());conn.setHostnameVerifier(new TrustAnyHostnameVerifier());conn.setRequestMethod("POST");conn.setRequestProperty("content-type", "text/json");conn.setRequestProperty("Proxy-Connection", "Keep-Alive");conn.setDoInput(true);conn.setDoOutput(true);BufferedOutputStream hurlBufOus = new BufferedOutputStream(conn.getOutputStream());//拼成固定的格式传给平台String str = String.format(Locale.CHINA, "{\"receipt-data\":\"" + receipt + "\"}");hurlBufOus.write(str.getBytes());hurlBufOus.flush();InputStream is = conn.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(is));String line = null;StringBuffer sb = new StringBuffer();while ((line = reader.readLine()) != null) {sb.append(line);}return sb.toString();}}

搞定收工,其实和正常支付流程来说不一样的是支付的工作都在苹果内部做好了,服务端只需要校验是否消费已经重复消费的问题就可以了!

最后加上沙盒测试环境苹果服务器返回的正确验证信息

{"environment":"Sandbox","receipt":{"in_app":[{"transaction_id":"1000000924533847","original_purchase_date":"2021-12-06 03:02:54 Etc/GMT","in_app_ownership_type":"PURCHASED","quantity":"1","original_transaction_id":"1000000924533847","purchase_date_pst":"2021-12-05 19:02:54 America/Los_Angeles","original_purchase_date_ms":"1638759774000","purchase_date_ms":"1638759774000","product_id":"test_001","original_purchase_date_pst":"2021-12-05 19:02:54 America/Los_Angeles","is_trial_period":"false","purchase_date":"2021-12-06 03:02:54 Etc/GMT"}],"adam_id":0,"receipt_creation_date":"2021-12-06 03:02:54 Etc/GMT","original_application_version":"1.0","app_item_id":0,"original_purchase_date_ms":"1375340400000","request_date_ms":"1639398803764","original_purchase_date_pst":"2013-08-01 00:00:00 America/Los_Angeles","original_purchase_date":"2013-08-01 07:00:00 Etc/GMT","receipt_creation_date_pst":"2021-12-05 19:02:54 America/Los_Angeles","receipt_type":"ProductionSandbox","bundle_id":"xxx.appx.iap","receipt_creation_date_ms":"1638759774000","request_date":"2021-12-13 12:33:23 Etc/GMT","version_external_identifier":0,"request_date_pst":"2021-12-13 04:33:23 America/Los_Angeles","download_id":0,"application_version":"1"},"status":0
}

Java 苹果支付applepay服务端验证相关推荐

  1. postman关闭ssl验证_【第5期】springboot:苹果内购服务端验证

    ​苹果内购: 只要你在苹果系统购买APP中虚拟物品(虚拟货币,VIP充值等),必须通过内购方式进行支付,苹果和商家进行三七开 验证模式有两种: Validating Receipts With the ...

  2. ios 自己服务器 苹果支付_苹果支付 PHP 服务端处理

    因为上周末连续加班 2 天(产品非要周一上线新版本),因此断更公众号一段时间,今天继续补上. 之前有了微信和支付宝支付后,产品要加上苹果支付,于是有了这篇文章. 一.ios 端流程 itunnes 相 ...

  3. 苹果支付php服务端处理,以及双重验证,收据,状态码

    以下是实际测试通过的苹果支付服务端代码,给大家提供些许思路帮助.再加强的安全处理根据自己的业务增加即可,这儿只列出了可用的骨架. public function applepayAction(){$r ...

  4. golang 苹果登录,服务端验证identityToken(真实有效)

    介绍 2019年之后,对于Apple App来说,如果要支持第三方登录,则必须同时支持苹果的第三方登录,即Sign in With Apple, 本文主要介绍如何使用Go语言实现Sign in Wit ...

  5. 苹果授权登陆 服务端验证(java)

    需要的jar包: jose4j-0.6.4.jar:jwks-rsa-0.9.0.jar:jjwt-0.9.1.jar: jar包下载地址:https://download.csdn.net/down ...

  6. java服务端验证谷歌支付Google Pay

    翻阅大半个谷歌,对服务器验证账单,讲的少之又少,还TM没有看懂 查阅整个百度,发现几乎所有demo都是用世界上最好的语言php写的,这我 在此坐下记录希望能帮到有需要的人 支付流程 前端支付完成,谷歌 ...

  7. Sign in with Apple(苹果授权登陆)服务端验证-测试通过版

    Sign in with Apple(苹果授权登陆)服务端验证-测试通过版 1.先引用2个jwt用到的jar包 2.算法的工具类 三方登录调用验证工具类 苹果登录方式有2种,这里介绍基于JWT算法验证 ...

  8. JSR-303 Bean Validation 介绍及 Spring MVC 服务端验证最佳实践

    任何时候,当要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情. 应用程序必须通过某种手段来确保输入参数在上下文来说是正确的. 分层的应用在很多时候,同样的数据验证逻辑会出现在不同的层, ...

  9. java的oauth2.0_[转]Java的oauth2.0 服务端与客户端的实现

    oauth原理简述 oauth本身不是技术,而是一项资源授权协议,重点是协议!Apache基金会提供了针对Java的oauth封装.我们做Java web项目想要实现oauth协议进行资源授权访问,直 ...

  10. Java的oauth2.0 服务端与客户端的实现

    oauth原理简述 oauth本身不是技术,而是一项资源授权协议,重点是协议!Apache基金会提供了针对Java的oauth封装.我们做Java web项目想要实现oauth协议进行资源授权访问,直 ...

最新文章

  1. java basedaoimpl_java web项目DAO层通用接口BaseDao与实现类BaseDaoImpl
  2. IOS开发:关于performSelectorXXX的延迟的使用
  3. druid配置数据库连接使用密文密码
  4. 给 Easyui Datagrid 扩展方法
  5. 如何保证战略落地_战略如何规划落地?值得借鉴
  6. 错误The request sent by the client was syntactically incorrect ()的解决
  7. 关于STM中SPI运用的NSS引脚解读
  8. 针对eclipse调式代码时打断点出现斜杠的解决方法
  9. grep和egrep的一些简单用法
  10. 五分钟学会python编程_每天五分钟python编程:生成器技术是python语言最强大的技术之一...
  11. myeclipse使用步骤总结
  12. 8086 CPU 寄存器
  13. 教你快速学习PID控制原理
  14. html div区域划分、居中各种前端技巧笔记
  15. 正则表达式-匹配中英文、字母和数字
  16. 腾讯开发者登录不上去
  17. 千年私服服务器用户名创建,千年私服详细安装技术文章
  18. Angular属性绑定,class绑定,事件绑定,属性样式绑定
  19. cv/dl/cl领域的实验室官网/牛人主页/技术论坛/比赛数据库/好玩的东西
  20. mac上最好用的在线视频播放器:IINA+ for Mac

热门文章

  1. 软考—软件设计师(软件工程基础知识)
  2. 开发者API资源(接口整理)
  3. 推荐几个移动端前端UI框架
  4. h5打开app指定页面,有则打开,无则下载
  5. 明华澳汉 sle_4442 卡 读写
  6. Google检索技巧大全
  7. arcgispython空间插值_[学习总结]如何利用GIS建模批量处理气象数据-以micaps 第四类数据空间插值为例-专业气象研究-气象家园_气象人自己的家园...
  8. visio UML图 视频学习
  9. 常用名词理解(APK,SDK,JDK,API,DLL)
  10. 必备电子技术经典资料汇总:基础入门篇1.6G