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+"\t"+"数量"+quantity+"\t"+"交易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;
	}
}

  

时间: 2024-10-12 05:30:37

In-App Purchases验证的相关文章

苹果开发——App内购以及验证store的收据(二)

原地址:http://zengwu3915.blog.163.com/blog/static/2783489720137605156966?suggestedreading 三. 客户端使用StoreKit完成内购 添加Storekit.Framework,编写自己的storeObsever,用于处理交易,代码如下,其中completeTransaction和failedTransaction两个函数是自定义的用来处理交易成功与失败其它的就都是SKPaymentTransactionObserv

App Store内购

一.In App Purchase概览 Store Kit代表App和App Store之间进行通信.程序将从App Store接收那些你想要提供的产品的信息,并将它们显示出来供用户购买.当用户需要购买某件产品时,程序调用StoreKit来收集购买信息.下图即为基本的store kit 模型: Store Kit的API只是为程序添加In App Purchase功能的一小部分.你需要决定如何去记录那些你想要提交的产品,如何在程序中将商店功能展现给用户,还要考虑如何将用户购买的产品提交.本章的剩

AppStore苹果应用支付开发(In App Purchase)翻译

http://yarin.blog.51cto.com/1130898/549141 一.In App Purchase概览 Store Kit代表App和App Store之间进行通信.程序将从App Store接收那些你想要提供的产品的信息,并将它们显示出来供用户购买.当用户需要购买某件产品时,程序调用StoreKit来收集购买信息.下图即为基本的store kit 模型: Store Kit的API只是为程序添加In App Purchase功能的一小部分.你需要决定如何去记录那些你想要提

IOS内购验证

客户端在沙箱环境下购买成功之后,需要进行二次验证 参考自:http://www.himigame.com/iphone-cocos2d/550.html 当应用向Apple服务器请求购买成功之后,Apple会返回数据给应用,如下所示: 产品标识符: product Identifier[在itunes store应用内定义的产品ID,例如com.公司名.产品名.道具名(com.xxxx.video.vip)] 交易状态: state Purchased 购买成功 Restored 恢复购买 Fa

ios 应用内支付(In-App Purchase,沙盒测试,后台验证)

1.苹果iTunes Connect内购产品信息录入. 1)创建app内购买项目(Create New),选择类型: 1.消耗型项目 对于消耗型 App 内购买项目,用户每次下载时都必须进行购买.一次性服务通常属于消耗型项目,例如钓鱼App 中的鱼饵. 2.非消耗型项目 对于非消耗型 App 内购买项目,用户仅需要购买一次.不会过期或随使用而减少的服务通常为非消耗型项目,例如游戏App 的新跑道. 3.自动续订订阅 通过自动续订订阅,用户可以购买指定时间期限内的更新和动态内容.除非用户取消选择,

Swift实现Touch ID验证

iOS8开放了很多API,包括HomeKit.HealthKit什么的.我们这里要说的是其中之一的Touch ID验证. 以前用app保护用户的隐私内容,只能设定和输入密码.眼看着只能是iPhone本身用Touch ID方便酷炫的解锁而自己的app不能.实在让人捉急.现在咱也可以酷炫一把了.当用户打开使用了Touch ID认证的app查看什么内容的时候就只能是把手指放在Home键上去验证身份.在app中验证的指纹就是用户在手机里的指纹.是的,你的app无需用户再输入一次验证用的指纹了.所以使用起

在xcode6.1和ios10.11环境下实现app发布

方法/步骤 1 第一步:创建app发布证书以及配置文件 1.  进入ios开发中心 2 2. 点击进入 Certificates,Identifiers & Profiles 3 3. 说明:因为这次我需要的是发布app,所以证书需要选择的是Production版本,而开发测试的话是Development版本. 4 4. 在Identifers中创建App IDs 说明: 这里就不做如何创建APP IDS的教程了,因为上次真机测试中已有,而已创建一个APP IDS中就包括了开发版(Develop

关于苹果purchase的验证

用户在购买苹果的商品的过程如下: 1.应用发送请求到服务器,获取所有的Products ID列表 2.服务器返回Products ID列表 3.应用发送请求至App Store,获取Products的信息 4.App Store返回Product信息 5.应用使用这些信息,向用户显示一个Store界面 6.用户从Store中选择一项 7.应用向App Store发送payment请求 8.App Store处理该payment,并返回完成的transaction 9.应用从transaction

【转】ios app 应用内购买配置完全指南

转自:http://blog.sina.com.cn/s/blog_4b55f6860100sbfb.html 第一印象觉得In-App Purchase(简称IAP)非常简单.Apple提供的大量文档应该让开发者很快熟悉地熟悉.那么,为什么在你的应用中集成IAP特性就如此令人生厌呢? 这是因为在开发过程中不可避免会出现一些错误.而但这些错误发生的时候,你就抓瞎了.虽然Apple提供了有关IAP的大量文档,但他们并未提及集成 IAP的详细步骤.而且对StoreKit集成过程中出现的问题也没有一个