支付憑證解析工具
import javax.net.ssl.*;
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;
/**
* 蘋果IAP內購驗證工具類
*/
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 支付憑證
* @param type 1=生產環境;0=沙盒環境
*/
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("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;
}
/**
* 用BASE64加密
*
* @param str
* @return
*/
public static String getBASE64(String str) {
byte[] b = str.getBytes();
String s = null;
if (b != null) {
s = new sun.misc.BASE64Encoder().encode(b);
}
return s;
}
}
下單和回調接口
import com.alibaba.fastjson.JSONObject;
import plugins.pay.ios.IosVerifyUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;
@RestController
@Api(tags="支付接口")
@RequestMapping("/Indent")
public class H5IndentController {
@GetMapping("/addIOS")
@ApiOperation(value = "iOS內購新增訂單", notes = "iOS內購新增訂單")
public String addWechat(HttpServletRequest request, HttpServletResponse response){
// TODO 保存數據
return "商戶訂單id";
}
/**
* 蘋果內購支付回調
* @param TransactionID 內購項目編號,不用管(感覺應該是每條支付憑證的一個唯一id,可以用來確定訂單是否處理)
* @param Payload BASE64的驗證字符串
* @param indentId 數據庫訂單id
*/
@PostMapping("/iosNotify")
public int doIosRequest(String TransactionID, String Payload, Long indentId) throws Exception {
// 解析支付憑證
String verifyResult = IosVerifyUtil.buyAppVerify(Payload,1);
if (verifyResult == null) {
return 10010;
} else {
// 獲取支付憑證狀態
JSONObject job = JSONObject.parseObject(verifyResult);
String states = job.getString("status");
// 沙盒環境
if("21007".equals(states)){
// 獲取沙盒環境憑證信息
verifyResult = IosVerifyUtil.buyAppVerify(Payload,0);
job = JSONObject.parseObject(verifyResult);
states = job.getString("status");
}
// 處理訂單
if (states.equals("0")) {
String receipt = job.getString("receipt");
JSONObject returnJson = JSONObject.parseObject(receipt);
String inApp = returnJson.getString("in_app");
List<HashMap> inApps = JSONObject.parseArray(inApp, HashMap.class);
if (!CollectionUtils.isEmpty(inApps)) {
// 循環處理訂單
for (HashMap app: inApps) {
// 查詢交易是否處理
String transactionId = (String) app.get("transaction_id");
// TODO 獲取到訂單id後,需要自行判斷這個訂單是否處理,transactionId這個值每個訂單時獨立的,但是iOS的
// 回調每次會把所有的訂單都返給回調接口,所有我沒要進行判斷
// TODO 處理業務邏輯
updateIndent(indentId + "", transactionId);
}
return 200;
}
return 10011;
} else {
return 10012;
}
}
}
}