苹果支付成功后,JAVA服务端二次验证

原理简述:

 苹果客户端在完成应用购买,下单后支付,苹果后台会给客户端返回信息,用来验证支付结果;
 客户端在拿到返回值后,将指定返回值,通过接口形式请求应用服务器,应用服务器根据这个值调用苹果服务器进行验证
应用服务器根据验证结果,来通知客户端支付成功与否。

需要客户端传的值:

[plain] view plain copy
  1. {"receipt-data" : "MIIaYAYJKoZIhvcNAQcC……"}具体未知见附件图片  

苹果支付成功后,JAVA服务端二次验证

支付信息验证地址:

[plain] view plain copy
  1. #苹果支付沙箱验证地址 :https://sandbox.itunes.apple.com/verifyReceipt  
  2. #苹果支付正式验证地址:https://buy.itunes.apple.com/verifyReceipt  

验证成功返回值样例:

后台可以通过判断返回的JSON传中status的值来简单判断支付成功与否,当然复杂一点可以加入价格校验
[plain] view plain copy
  1. {  
  2.   "status": 0,  
  3.   "environment": "Sandbox",  
  4.   "receipt": {  
  5.     "receipt_type": "ProductionSandbox",  
  6.     "adam_id": 0,  
  7.     "app_item_id": 0,  
  8.     "bundle_id": "com.platomix.MicroBusinessManage",  
  9.     "application_version": "2.0.0",  
  10.     "download_id": 0,  
  11.     "version_external_identifier": 0,  
  12.     "receipt_creation_date": "2017-06-06 06:35:27 Etc/GMT",  
  13.     "receipt_creation_date_ms": "1496730927000",  
  14.     "receipt_creation_date_pst": "2017-06-05 23:35:27 America/Los_Angeles",  
  15.     "request_date": "2017-06-06 07:13:26 Etc/GMT",  
  16.     "request_date_ms": "1496733206549",  
  17.     "request_date_pst": "2017-06-06 00:13:26 America/Los_Angeles",  
  18.     "original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",  
  19.     "original_purchase_date_ms": "1375340400000",  
  20.     "original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",  
  21.     "original_application_version": "1.0",  
  22.     "in_app": []  
  23.  }  
  24. }  

验证失败返回值说明:

[java] view plain copy
  1. 服务器二次验证代码  
  2.         * 21000 App Store不能读取你提供的JSON对象  
  3.         * 21002 receipt-data域的数据有问题  
  4.         * 21003 receipt无法通过验证  
  5.         * 21004 提供的shared secret不匹配你账号中的shared secret  
  6.         * 21005 receipt服务器当前不可用  
  7.         * 21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送  
  8.         * 21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务  
  9.         * 21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务  

服务端源码:

[java] view plain copy
  1. /**  
  2.      * 向指定 URL 发送POST方法的请求  
  3.      *   
  4.      * @param url  
  5.      *            发送请求的 URL  
  6.      * @param param  
  7.      *            请求参数,请求参数应该是 name1=value1&name2=value2 的形式。  
  8.      * @return 所代表远程资源的响应结果  
  9.      */    
  10.     public static  synchronized JSONObject sendPost(String url, JSONObject param) {   
  11.           
  12.            
  13.         StringBuilder sb = new StringBuilder();    
  14.         PrintWriter out = null;    
  15.         BufferedReader in = null;    
  16.         try {    
  17.             URL realUrl = new URL(url);    
  18.             // 打开和URL之间的连接    
  19.             URLConnection conn = realUrl.openConnection();    
  20.             // 设置通用的请求属性    
  21.             conn.setRequestProperty("accept""*/*");    
  22.             conn.setRequestProperty("connection""Keep-Alive");    
  23.             conn.setRequestProperty("user-agent""Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");    
  24.             // 发送POST请求必须设置如下两行    
  25.             conn.setDoOutput(true);    
  26.             conn.setDoInput(true);    
  27.             // 获取URLConnection对象对应的输出流    
  28.             out = new PrintWriter(conn.getOutputStream());    
  29.             // 发送请求参数    
  30.             out.print(param);    
  31.             // flush输出流的缓冲    
  32.             out.flush();    
  33.             // 定义BufferedReader输入流来读取URL的响应    
  34.             in = new BufferedReader(new InputStreamReader(conn.getInputStream()));    
  35.             String line;    
  36.             sb = new StringBuilder();   
  37.               
  38.             while ((line = in.readLine()) != null)   
  39.             {  
  40.                 sb.append(line);    
  41.             }    
  42.         } catch (Exception e) {    
  43.            // System.out.println("发送 POST 请求出现异常!"+e);    
  44.             e.printStackTrace();    
  45.         }    
  46.         //使用finally块来关闭输出流、输入流    
  47.         finally{    
  48.             try{    
  49.                 if(out!=null){    
  50.                     out.close();    
  51.                 }    
  52.                 if(in!=null){    
  53.                     in.close();    
  54.                 }    
  55.             }    
  56.             catch(IOException ex){    
  57.                 ex.printStackTrace();    
  58.             }    
  59.         }    
  60.         return JSON.parseObject((String) sb.toString());    
  61.     }     

请求样例:(POST)

[plain] view plain copy
  1. {  
  2.     "receipt-data": "MIIaYAYJKoZIhvcNAQcCoIIaUTCCGk0CAQExCzAJBgUrDgMCGgUAMIIKAQYJKoZIhvcNAQcBoIIJ8gSCCe4xggnqMAoCAQgCAQEEAhYAMAoCARQCAQEEAgwAMAsCAQECAQEEAwIBADALAgELAgEBBAMCAQAwCwIBDwIBAQQDAgEAMAsCARACAQEEAwIBADALAgEZAgEBBAMCAQMwDAI……}  
需要注意的是,必须安装上面的入参样例 "receipt-data“ 注意是中横线,具体请求,我做了截图,详见附件

苹果支付成功后,JAVA服务端二次验证