苹果支付Java后台总结

官方地址:https://developer.apple.com/apple-pay/sandbox-testing/

简介

初次接触苹果支付,首先要搞懂流程。苹果支付不同于支付宝,微信支付。

比较微信支付与苹果支付的支付流程:

  • 微信支付:客户端支付——>微信——>微信提现——>银行账户。
    1. 如果你不提现,所有的收益都在微信平台;如果提现,微信平台就要收取相关的手续费,具体手续费跟行业不同有差异。这也是微信平台的直接收益。
    2. 微信支付通过服务端api调用实现。
  • 苹果支付:客户端支付——>商户银行账户。
    1. 它是通过客户端(苹果设备)将用户银行卡上的钱直接转到商户的银行账户上。因为钱没有第三方(苹果)经手,所以,苹果支付没有像支付宝、微信一样有直接收益。为了维护这套服务功能,苹果需要在有支付功能的应用上收取相应的提成。具体收费情况也要根据具体的产品内容有关。如有实物,可能就不需要提成。如软件需要开通会员等虚拟服务,就需要收取近3成的费用。详情去官方文档查询。
    2. 苹果支付通过苹果设备(iphone等)支付,前端支付,不需要走服务端,但需要在服务端验证支付结果。

支付接口

接口与验证

    /**
	 * 苹果端APP订单支付成功回调
	 * @param userId 用户ID
	 * @param receipt 前台传过来的苹果支付收据简码,是base64加密参数。
	 */
	@RequestMapping(value = "/*****")
	public @ResponseBody Map<String,Object> iosPaymentSuccess(HttpServletRequest request,
			@RequestParam(name="userId", required=true)int userId,@RequestParam(required=true) String receipt){
		Map<String, Object> resultMap =new HashMap<String, Object>();
		try {
			logger.info("苹果支付:receipt=="+receipt);
			//校验用户是否存在
			User user = userService.queryUserById(userId);
			if (user == null){  
				resultMap=createResults(ErrorCode.ACCOUNT_USERID_INVALIDURL);
				resultMap.put("success", false);
				return resultMap;
			}
			//验证苹果收据是否有效
			Map<String,Object> verifyMap = iPayNotify(receipt);
			if(!(boolean)verifyMap.get("success")){//验证失败,直接返回失败信息
				resultMap = createResults(ErrorCode.IOS_PAY_VERIFY_FAILED);
				resultMap.put("success", false);
				return resultMap;
			}
			String verifyResult = (String) verifyMap.get("verifyResult");//苹果返回的收据信息




			/*********************此处写验证成功后的逻辑*******************/




			//返回处理结果
			resultMap = createResults(ErrorCode.API_SUCCESS);
			resultMap.put("success",true);
		} catch (Exception e) {
			resultMap=createResults(ErrorCode.FAILED);
        	resultMap.put("success",false);
		}
		return resultMap;
	}
	/**
	 * 验证苹果收据是否有效
	 * @param receipt
	 * @return
	 */
	public Map<String,Object> iPayNotify(String receipt) {
		Map<String,Object> map = new HashMap<String,Object>();
		// 1.先线上测试    发送平台验证
		String verifyResult = IosVerifyUtil.buyAppVerify(receipt, 1);
		if (verifyResult == null) {// 苹果服务器没有返回验证结果
			map.put("success", false);
			return map;
		} else {// 苹果验证有返回结果
			JSONObject job = JSONObject.parseObject(verifyResult);
			String states = job.getString("status");
			//2、是沙盒环境,验证沙盒测试
			if ("21007".equals(states)) {
				// 3.再沙盒测试  发送平台验证
				verifyResult = IosVerifyUtil.buyAppVerify(receipt, 0);
				job = JSONObject.parseObject(verifyResult);
				states = job.getString("status");
			}
			//收据线上验证有效,本地验证
			if ("0".equals(states)) {
				// 4、查询数据库,看是否是己经验证过的该支付收据 
				JSONObject verifyResultJson = JSONObject.parseObject(verifyResult);
				JSONObject receiptJson = verifyResultJson.getJSONObject("receipt");
				JSONArray inApp2 = receiptJson.getJSONArray("in_app");
				JSONObject inApp = JSONObject.parseObject(inApp2.getString(0));
				String outTradeNo = inApp.getString("transaction_id");//收据唯一标识
				
				int receiptIsExis = orderService.checkTradeNoIsExist(outTradeNo);
				if(receiptIsExis != 0){//已经存在的订单收据无效
					map.put("success", false);
					return map;
				}
				map.put("verifyResult", verifyResult);
				map.put("success", true);
				return map;
			}else{
				map.put("success", false);
				return map;
			}
		}
		
	}

验证工具类:

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Locale;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * @desc: 苹果IAP内购验证工具类
 * @author: QDC
 * @date: 2021/03/09
 */
public class IosVerifyUtil {

    private static class TrustAnyTrustManager implements X509TrustManager {

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        }

        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }

    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        public 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) {
        //环境判断 线上/开发环境用不同的请求链接
        String url = "";
        if (type == 0) {
            url = url_sandbox; //沙盒测试
        } else {
            url = url_verify; //线上测试
        }
        //String url = EnvUtils.isOnline() ?url_verify : url_sandbox;

        try {
            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("Content-Type", "application/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();
        } catch (Exception ex) {
            System.out.println("苹果服务器异常");
            ex.printStackTrace();
        }
        return null;
    }

    
}

ps:附上返回收据的示例。

大超 11:30:52
{
    "status": 0,
    "environment": "Production",
    "receipt": {
        "receipt_type": "Production",
        "adam_id": 2341443613,
        "app_item_id": 2234443613,
        "bundle_id": "com.xxxxx.xxxxx",
        "application_version": "1",
        "download_id": 23456572706673,
        "version_external_ident ifier": 821223402,
        "receipt_creation_date": "2017-01-25 00:52:37 Etc/GMT",
        "receipt_creation_date_ms": "3333897657000",
        "receipt_creation_date_pst": "2017-01-25 17:57:37 America/Los_Angeles",
        "request_date": "2017-01-26 00:57:38 Etc/GMT",
        "request_date_ms": "1445897657000",
        "request_date_pst": "2017-05-29 17:57:38 America/Los_Angeles",
        "original_purchase_date": "2016-01-25 15:37:18 Etc/GMT",
        "original_purchase_ date_ms": "145234568000",
        "original_purchase_date_pst": "2016-01-25 07:37:18 America/Los_Angeles",
        "original_application_version": "12",
        "in_app": [
             {
                 "quantity": "1",
                 "product_id": "xxxxxxxxx",//留存在苹果应用商店产品id
                 "transaction_id": "110000290198443",//收据唯一标识
                 "original_transaction_id": "110000290198443",
                 "purchase_date": "2017-01-26 00:23:36 Etc/GMT",
                 "purchase_date_ms": "1496105856000",
                 "purchase_date_pst": "2017-01-26 00:35:30 America/Los_Angeles",
                 "original_purchase_date": "2017-01-26 00:57:36 Etc/GMT",
                 "original_purchase_date_ms": "14347896000",
                 "original_purchase_date_pst": "2017-01-25 17:57:36 America/Los_Angeles",
                 "is_trial_period": "false"
             }
         ]
     }
}

猜你喜欢

转载自blog.csdn.net/dachao_com/article/details/115068345