In-App Purchases验证

package com.demo.controller.web.app;

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.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

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;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import sun.misc.BASE64Decoder;

import com.demo.common.Result;
import com.demo.common.util.StringUtils;
import com.demo.constant.Constant;
import com.demo.constant.Enums;
import com.demo.service.AppEspOrderService;
import com.demo.service.AppEspProductService;
import com.demo.service.AppUserInfoService;
import com.demo.service.AppVersionService;
import com.demo.service.UserService;
import com.demo.service.eshop.EspOrderLogService;
import com.demo.vo.AppEspOrder;
import com.demo.vo.AppEspProduct;
import com.demo.vo.AppUserInfo;
import com.demo.vo.AppVersion;
import com.demo.vo.EspOrderLog;
import com.demo.vo.User;

import net.sf.json.JSONObject;

@Controller
@RequestMapping("/app/*")
public class AstroCalendarIOSVerifyController {
	private Logger log = Logger.getLogger(AstroCalendarIOSVerifyController.class);
	@Autowired
	private UserService userService;
	@Autowired
	private AppEspOrderService appEspOrderService;
	@Autowired
	private AppVersionService appVersionService;
	@Autowired
	private AppEspProductService appEspProductService;	
	@Autowired
	private AppUserInfoService appUserInfoService;
	@Autowired
	private EspOrderLogService espOrderLogService;

	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	账单
	 * @url 要验证的地址
	 * @return null 或返回结果 沙盒 https://sandbox.itunes.apple.com/verifyReceipt
	 * 
	 */
	public String buyAppVerify(String receipt,String url,Map<String, String> map) {
		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);
			conn.setConnectTimeout(30*1000);//设置连接超时30秒
			BufferedOutputStream hurlBufOus = new BufferedOutputStream(conn.getOutputStream());

			String str = String.format(Locale.CHINA, "{"receipt-data":""+ receipt + ""}");
			System.out.println("str:" + str);
			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);
			}
			System.out.println(sb.toString());
			return sb.toString();
		} catch (Exception ex) {
			log.error("系统异常"+ex);
			map.put("orderStatus", "D");
//			ex.printStackTrace();
		}
		return null;
	}

	@RequestMapping("/app/validateOrder" + Constant.JSON)
	@ResponseBody
	public Map<String, String> validateOrder(HttpServletRequest request) {
		long start = System.currentTimeMillis();
		Map<String, String> map = new HashMap<String, String>();
		User user = checkUserLogin(request);
		AppUserInfo appUser = null;
		if(user!=null){
			appUser = new AppUserInfo();
			appUser.setUserId(user.getUserId());
			appUser = appUserInfoService.findByPk(appUser);
		}
		//判断app用户表里是否存在此用户
		if(appUser == null){
			map.put("loginStatus", "-1");
		}else{
			map.put("loginStatus", "0");
			try {
				String receipt = request.getParameter("receipt");
				String orderMonths = request.getParameter("orderMonths");
				String versionCode = request.getParameter("versionCode");
				String appId = request.getParameter("appId");
				String price = request.getParameter("price");
				if(StringUtils.isBlank(appId) || StringUtils.isBlank(versionCode)){
					map.put("orderStatus", "D");
					return map;
				}
				Integer vCode = Integer.parseInt(versionCode);
				Integer appID = Integer.parseInt(appId);
				
				AppEspOrder aeo = new AppEspOrder();
				aeo.setReceipt(receipt);
				List<AppEspOrder> list = appEspOrderService.freeFindAll(aeo);
				if(list.size()==0){
					//添加新订单
					AppUserInfo aui = new AppUserInfo();
					aui.setUserId(user.getUserId());
					aui = appUserInfoService.findByPk(aui);
					SimpleDateFormat osf = new SimpleDateFormat("yyMMddHH");
					String orderId = Enums.OrderPrefix.NA + osf.format(new Date())+ StringUtils.getRandomSixNUM();
					if(aui != null){
						AppVersion version = new AppVersion();
						version.setVersionCode(vCode);
						int count = appVersionService.countFreeFind(version);
						
						AppEspProduct aep = new AppEspProduct();
						aep.setAppId(appID);
						aep = appEspProductService.findByPK(aep);
						//检查appID,versionId是否合法
						if(aep == null || count<0){
							map.put("orderStatus", "C");
							return map;
						}
						aeo.setAppId(aep.getAppId());
						aeo.setAppName(aep.getAppName());
						aeo.setVersionCode(vCode);
						aeo.setUserId(aui.getUserId());
						aeo.setNickName(aui.getNickName());
						aeo.setEmail(aui.getEmail());
						aeo.setOrderId(orderId);
						aeo.setOrderMonths(orderMonths);
						aeo.setSubtotal(new Long(price));
						aeo.setIsFree("N");
						aeo.setOrderStatus("A");//新订单
						aeo.setCreateBy("system");
						aeo.setCreateDt(new Date());
						aeo.setPaidDate(new Date());
						appEspOrderService.insert(aeo);
						
						//订单日志
						EspOrderLog log = new EspOrderLog();
						log.setRemark("生成新订单,已支付,等待验证...");
						log.setChangeTime(new Date());
						log.setChangeUser("system");
						log.setIsMem("N");
						log.setType("A");
						log.setOrderId(orderId);
						espOrderLogService.addOrderLog(log);
					}
					//向苹果服务器发起验证
					Result result = validateAppleServler(map, receipt, url_verify, aeo, orderId);
					if(result.isSuccess()==true){
						validateAppleServler(map, receipt, url_sandbox, aeo, orderId);
					}
				}else{//如果该收据已经存在,判断收据的订单状态,再判断是用户及月份是否相同,防止盗用receipt
					AppEspOrder order = list.get(0);
					if("A".equals(order.getOrderStatus()) || "D".equals(order.getOrderStatus())){//新订单已经添加尚未验证或验证超时连接错误,需重新请求验证
						Result result = validateAppleServler(map, order.getReceipt(), url_verify, order, order.getOrderId());
						if(result.isSuccess()==true){
							validateAppleServler(map, order.getReceipt(), url_sandbox, order, order.getOrderId());
						}
					}else if("B".equals(order.getOrderStatus())){
						if(receipt.equals(order.getReceipt())&&user.getUserId().equals(order.getUserId())&&orderMonths.equals(order.getOrderMonths())){
							map.put("orderStatus", "B");
						}else{
							map.put("orderStatus", "C");//验证失败
						}
					}else{
						map.put("orderStatus", "C");//验证失败
					}
					}
			} catch (Exception e) {
				map.put("orderStatus", "D");
				log.error("系统异常"+e);
				e.printStackTrace();
			}
			}
		long end = System.currentTimeMillis();
		System.out.println("验证收据信息耗时:"+(end-start)+"毫秒");
		return map;
	}
	//向苹果服务器发送验证请求
	private Result validateAppleServler(Map<String, String> map, String receipt, String url, AppEspOrder aeo, String orderId) {
		Result result = new Result().setSuccess(false);
		String verifyResult = buyAppVerify(receipt,url,map);
		if (verifyResult != null) {
			JSONObject job = JSONObject.fromObject(verifyResult);
			String status = job.getString("status");
			if ("0".equals(status)){// 验证成功
				aeo.setOrderStatus("B");
				
				String r_receipt=job.getString("receipt");  
				System.out.println(r_receipt);
				System.out.println("-------------------------------");
                JSONObject returnJson = JSONObject.fromObject(r_receipt);  
                String product_id = returnJson.getString("product_id");  //产品ID  
                String quantity = returnJson.getString("quantity"); //数量  
                String transactionId = returnJson.getString("transaction_id");//交易id
				System.out.println("产品id:"+product_id+"	"+"数量"+quantity+"	"+"交易id"+transactionId);
				aeo.setProductId(product_id);
				int total = 0;
				if(!StringUtils.isBlank(quantity))
					total = Integer.parseInt(quantity);
				aeo.setQuantity(total);
				aeo.setTransactionId(transactionId);
				appEspOrderService.update(aeo);
				
				EspOrderLog log2 = new EspOrderLog();
				log2.setRemark("向苹果服务器发送验证成功...");
				log2.setChangeTime(new Date());
				log2.setChangeUser("system");
				log2.setIsMem("N");
				log2.setType("B");
				log2.setOrderId(orderId);
				espOrderLogService.addOrderLog(log2);
				map.put("orderStatus", "B");
			}else if("21007".equals(status)){//重新验证,更改路径为正式环境的路径
				
				EspOrderLog log1 = new EspOrderLog();
				log1.setRemark("向苹果正式服务器发送验证失败,得到状态值为21007.");
				log1.setChangeTime(new Date());
				log1.setChangeUser("system");
				log1.setIsMem("N");
				log1.setType("A");
				log1.setOrderId(orderId);
				espOrderLogService.addOrderLog(log1);
				result.setSuccess(true);
			}else{//验证失败
				aeo.setOrderStatus("C");
				appEspOrderService.update(aeo);
				
				EspOrderLog log1 = new EspOrderLog();
				log1.setRemark("向苹果服务器发送验证失败...");
				log1.setChangeTime(new Date());
				log1.setChangeUser("system");
				log1.setIsMem("N");
				log1.setType("A");
				log1.setOrderId(orderId);
				espOrderLogService.addOrderLog(log1);
				map.put("orderStatus", "C");
			}
		}
		return result;
	}
	private User checkUserLogin(HttpServletRequest request) {
		String username = request.getParameter("username");
		String password = request.getParameter("password");
		if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
			return null;
		}
		User user = new User();
		try {
			user.setEmail(username);
			user.setPassword(password);
			user = userService.userLogin(user);

		} catch (Exception e) {
			log.error("登录失败,用户名或密码错误!" + e);
		}
		return user;
	}
}

  

原文地址:https://www.cnblogs.com/youngjoy/p/4681554.html