package com.ljsd.channel; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.ljsd.util.BaseGlobal; import com.ljsd.util.TimeUtil; import com.ljsd.util.XmlParser; import com.mongodb.BasicDBObject; import com.mongodb.DBObject; import org.apache.http.HttpEntity; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; public class Mock361YXSDK { private static final Logger LOGGER = LoggerFactory.getLogger(Mock361YXSDK.class); private static final String APP_ID="39bee2c821834c32"; private static final String LOGIN_KEY="3dc60d6756c04f4ca23c6addba1e400e"; private static final String PAY_KEY="befa74b8ed734b01afb34b64f56c8cc2"; private static final String VERIFY_API_URL="http://sdk.361yx.com/tools/gamefactor.ashx?action=factor_login"; private static final CloseableHttpClient httpClient = HttpClients.createDefault(); private final static String _COLLECTION_PAY = "pay"; private static final Gson GSON = new Gson(); public static boolean verifyUser(String uid) { try { Map params = new HashMap<>(); params.put("app_id",APP_ID); params.put("uid",uid); params.put("timestamp",String.valueOf(TimeUtil.getTimeNow())); params.put("pay_key", PAY_KEY); // 构建排序后的查询字符串 String sortedQuery = buildSortedQuery(params); LOGGER.info("排序后的查询字符串:{}", sortedQuery); String sign = md5(sortedQuery); // 域名+/tools/gamefactor.ashx?action=factor_login List formParams = new ArrayList<>(); formParams.add(new BasicNameValuePair("app_id", APP_ID)); // app_id 参数 formParams.add(new BasicNameValuePair("uid", uid)); // uid 参数 formParams.add(new BasicNameValuePair("timestamp", params.get("timestamp"))); // timestamp 参数 formParams.add(new BasicNameValuePair("sign", sign)); HttpPost httpPost = new HttpPost(VERIFY_API_URL); UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(formParams, StandardCharsets.UTF_8); httpPost.setEntity(formEntity); CloseableHttpResponse response = httpClient.execute(httpPost); String responseStr = EntityUtils.toString(response.getEntity(), "UTF-8"); JsonObject jsonObject = GSON.fromJson(responseStr, JsonObject.class); int status = jsonObject.get("status").getAsInt(); String realname = jsonObject.has("realname") ? jsonObject.get("realname").getAsString() : null; String idcard = jsonObject.has("idcard") ? jsonObject.get("idcard").getAsString() : null; String msg = jsonObject.has("msg") ? jsonObject.get("msg").getAsString() : null; response.close(); if (status == 1) { LOGGER.info("验证成功!真实姓名:{},身份证号:{}", realname, idcard); return true; } else { LOGGER.error("验证失败,原因:{}", msg); return false; } } catch (Exception e) { e.printStackTrace(); LOGGER.error("361yx 验证异常:", e); return false; } } public static String md5(String input) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] hashBytes = md.digest(input.getBytes(StandardCharsets.UTF_8)); StringBuilder hexString = new StringBuilder(); for (byte b : hashBytes) { String hex = Integer.toHexString(0xFF & b); if (hex.length() == 1) { hexString.append('0'); // 补前导零(如 0x0A → "0a") } hexString.append(hex); } return hexString.toString(); } public static boolean verifyCallback(Map params, String sign) throws NoSuchAlgorithmException { params.put("pay_key", PAY_KEY); // 包含特殊字符 // 构建排序后的查询字符串 String sortedQuery = buildSortedQuery(params); LOGGER.info("排序后的查询字符串:{}", sortedQuery); String signCheck = md5(sortedQuery); LOGGER.info("signCheck:{}", signCheck); return signCheck.equals(sign.toLowerCase()); } public static String buildSortedQuery(Map params) { // 1. 分离 pay_key 和其他参数(其他参数需非空) Map otherParams = new HashMap<>(); String payKeyValue = params.get("pay_key"); // 过滤其他参数(非 pay_key 且值非空) for (Map.Entry entry : params.entrySet()) { String key = entry.getKey(); String value = entry.getValue(); if (!"pay_key".equals(key) && value != null && !value.trim().isEmpty()) { otherParams.put(key, value); } } // 2. 对其他参数按键的 ASCII 字典序排序 List sortedOtherKeys = otherParams.keySet().stream() .sorted() // 按 String 自然顺序(ASCII 字典序)排序 .collect(Collectors.toList()); // 3. 拼接其他参数(已排序) StringBuilder otherParamsStr = new StringBuilder(); for (String key : sortedOtherKeys) { String value = otherParams.get(key); try { String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8.name()); otherParamsStr.append(key).append("=").append(encodedValue).append("&"); } catch (UnsupportedEncodingException e) { // 理论上不会触发,此处处理异常 otherParamsStr.append(key).append("=").append(value).append("&"); } } // 移除末尾多余的 & if (otherParamsStr.length() > 0) { otherParamsStr.deleteCharAt(otherParamsStr.length() - 1); } // 4. 拼接 pay_key(始终在最后) StringBuilder finalQuery = new StringBuilder(otherParamsStr); // 初始化为其他参数的拼接结果 // 拼接 pay_key(如果有值) if (payKeyValue != null && !payKeyValue.trim().isEmpty()) { try { String encodedPayKey = URLEncoder.encode(payKeyValue, StandardCharsets.UTF_8.name()); if (finalQuery.length() > 0) { finalQuery.append("&").append("pay_key=").append(encodedPayKey); } else { finalQuery.append("pay_key=").append(encodedPayKey); } } catch (UnsupportedEncodingException e) { if (finalQuery.length() > 0) { finalQuery.append("&").append("pay_key=").append(payKeyValue); } else { finalQuery.append("pay_key=").append(payKeyValue); } } } return finalQuery.toString(); } public static DBObject saveDB(Map params) throws Exception { LOGGER.info("params = {}", params); String orderId = params.get("cp_order_id"); DBObject payInfo = new BasicDBObject(); payInfo.put("cporderId", orderId); List payInfoList = BaseGlobal.getInstance().mongoDBPool.find(_COLLECTION_PAY, payInfo); if (payInfoList.size() != 1) { LOGGER.error("payInfoList.size() = {}", payInfoList.size()); return null; } payInfo = payInfoList.get(0); // 比较订单金额 BigDecimal money = new BigDecimal(params.get("order_amount")); int processedMoney = money.multiply(BigDecimal.valueOf(100)) .intValueExact(); int amount = (int) payInfo.get("money"); boolean isEqual = processedMoney == amount; LOGGER.info("处理后的金额(100倍)= {}", processedMoney); LOGGER.info("与目标金额对比结果= {}, 订单金额 = {}", isEqual, amount); if(!isEqual) { LOGGER.error("金额不一致,请检查!"); return null; } payInfo.put("billno", orderId); // payInfo.put("uid", request.getParameter("role_id")); payInfo.put("openId", params.get("open_id")); payInfo.put("region", params.get("server_id")); payInfo.put("channel", "361yx"); payInfo.put("gameorderId", params.get("order_id")); // dbObject.put("cporderId", platform); // payInfo.put("creattime",request.getParameter("pay_time")); payInfo.put("callbaktime", TimeUtil.getTimeNow()); BaseGlobal.getInstance().mongoDBPool.save(_COLLECTION_PAY, payInfo); return payInfo; } private static String generateSign(String appId, String appSecret, String userId) { String raw = appId + appSecret + userId; return raw.hashCode() + ""; } }