123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
import java.io.IOException;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.net.MalformedURLException;import java.net.URL;import java.net.URLConnection;import java.net.URLDecoder;import java.net.URLEncoder;import java.security.InvalidKeyException;import java.security.KeyFactory;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.security.PublicKey;import java.security.Signature;import java.security.SignatureException;import java.security.spec.InvalidKeySpecException;import java.security.spec.X509EncodedKeySpec;import java.util.Base64;import java.util.HashMap;import java.util.Map;import java.util.Scanner;import java.util.SortedSet;import java.util.TreeSet;public class ServerDemo { private static String verifyLoginUrl = "https://cn-api.unity.com/v1/login-attempts/verifyLogin"; private static String checkOrderUrl = "https://cn-api.unity.com/v1/order-attempts/query"; private static String charset = "UTF-8"; private static String clientSecret = "Your Unity Client Secret Here."; private static String RSAPublicKey = "Your Unity RSA Public Key Here."; public static void main(String[] args) { // verify login sample try { String userLoginToken = "Please get user login token in Unity IAP SDK."; Map<String, String> parameters = new HashMap<String, String>(); parameters.put("userLoginToken", userLoginToken); String verifyLoginResponse = sendRequest(parameters, verifyLoginUrl); System.out.println(verifyLoginResponse); } catch (Exception e) { e.printStackTrace(); } // check order status sample try { String orderQueryToken = "Please get order query token in Unity IAP SDK."; Map<String, String> parameters = new HashMap<String, String>(); parameters.put("cpOrderId", "Please get cpOrderId in Unity IAP SDK."); parameters.put("clientId", "Your Unity Client Id Here."); parameters.put("orderQueryToken", orderQueryToken); String verifyLoginResponse = sendRequest(parameters, checkOrderUrl); System.out.println(verifyLoginResponse); } catch (Exception e) { e.printStackTrace(); } // RSA verify for callback sample try { String query = "callback query string (signData=...&signature=...) from Unity IAP server"; String response = receiveCallback(query); System.out.println(response); } catch (Exception e) { e.printStackTrace(); } } /** send request to Unity IAP server. * @param parameters the query parameters * @param url the Unity IAP api url * @return api response * @throws MalformedURLException * @throws IOException */ private static String sendRequest(Map<String, String> parameters, String url) throws MalformedURLException, IOException { String ret = ""; String signData = ""; String query = ""; // sort parameters SortedSet<String> keys = new TreeSet<String>(parameters.keySet()); for (String key : keys) { String value = parameters.get(key); signData += value + "&"; query += key + "=" + URLEncoder.encode(value, charset) + "&"; } signData += clientSecret; // sign parameters String sign = md5Sign(signData); query += "sign=" + sign; URLConnection connection = new URL(url + "?" + query).openConnection(); connection.setRequestProperty("Accept-Charset", charset); InputStream response = connection.getInputStream(); try (Scanner scanner = new Scanner(response)) { String responseBody = scanner.useDelimiter("\\A").next(); ret += responseBody; } return ret; } /** MD5 signature for given string * @param signData the string to be signed * @return */ private static String md5Sign(String signData) { String passwordHash = null; try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] bytes = md.digest(signData.getBytes()); StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1)); } passwordHash = sb.toString(); } catch (Exception e) { e.printStackTrace(); } return passwordHash; } /** receive Unity IAP server's callback request * @param query the request query string (signData=...&signature=...) * @return the response string ("ok" for success or others for failure) * @throws UnsupportedEncodingException * @throws InvalidKeyException * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws SignatureException */ private static String receiveCallback(String query) throws UnsupportedEncodingException, InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, SignatureException { Map<String, String> parameters = new HashMap<String, String>(); for (String param : query.split("&")) { String pair[] = param.split("="); if (pair.length>1) { String value = URLDecoder.decode(pair[1], charset); parameters.put(pair[0], value); } } String signDataValue = parameters.get("signData"); String signValue = parameters.get("signature"); if (signDataValue != null && signValue != null) { if(verifyRsa(signDataValue, signValue, RSAPublicKey)) { return "ok"; } } return "not ok"; } /** verify the signData with signature by RSA * @param signData signData string * @param sign signature string * @param key RSA public key * @return true if verified successfully, otherwise false * @throws NoSuchAlgorithmException * @throws InvalidKeySpecException * @throws InvalidKeyException * @throws SignatureException */ private static boolean verifyRsa(String signData, String sign, String key) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException { byte[] keyBytes = Base64.getDecoder().decode(key); X509EncodedKeySpec pkcs8KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory fact = KeyFactory.getInstance("RSA"); PublicKey pubKey = fact.generatePublic(pkcs8KeySpec); Signature signature = Signature.getInstance("SHA1WithRSA"); signature.initVerify(pubKey); signature.update(signData.getBytes()); return signature.verify(Base64.getDecoder().decode(sign)); }}