using System; using System.Collections.Generic; using System.Net.Http; using System.Text; using Sog; using LitJson; using ProtoCSStruct; using Sog.Crypto; using Sog.Service; using System.Text.Json; namespace HttpProxyPay { public class HuaweiPaySvc { // paysvr部署在美国, 华为推荐选择德国站点 private static string _PayCheckUrl = "https://orders-dre.iap.hicloud.com/applications/purchases/tokens/verify"; private static string _GetTokenUrl = "https://oauth-login.cloud.huawei.com/oauth2/v3/token"; // 游戏产品在SDK平台的应用ID private static string ClientId = "105624843"; // 游戏产品在SDK平台的应用私钥 private static string ClientSecret = "1913208d8b4d11a0d9c1c3c096318ad84c8a41ef9105313ea5f2ad245ebc5d96"; // 支付公钥 private static string PayPublicKey = "MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAk9kJsng7rYIHhm+MXGjWg2BIl8i5cMs7jiQrkc9FlD0hCvmIJv/nIS2ZLMGVri0mVjzwbeR6YABjcSN1SYuwkjoSN4aEKGh8be3CAoJgMSj87boqiZwhOa2dCXHqtSB0Zqd9iqfFm9COVC0Y/CE2Rh9DW/ku6iltiGhP1+Zze9bXp4lnH/OcLcJEaReKESEZajwvv6po7pNzqEqO0S+wMy5shZcQZNmmjB6pTpei5DJUHOdjDEE1+OiWdVa1yA2z53JP11UABjQhZdSiEvPeGkNusuyWsgtIEun2VvwWt5drLOSrMekUmwq3Q3k/BRfR+o1pnDiatpt7TYMmadC7NTgkn6SPzzT0zHnPa9jZJdWKcLT3Z7YJP41pHMbWvGgB3Vm6bErFjBMm5nrgOT7bQvieU9KUbLiA3Y1jFredxxpsUh3lglU4gjN2CaDFNI1gMX0myliiQZsudKkrFNuwkqHuRnEcy8S/FcXK+aX4zDHu5jm0vfQJX8mot+ee22HvAgMBAAE="; public static void Init(string clientId, string clientSecret, string payCheckUrl, string getTokenUrl) { if (! string.IsNullOrEmpty(clientId)) { ClientId = clientId; } if (! string.IsNullOrEmpty(clientSecret)) { ClientSecret = clientSecret; } if (! string.IsNullOrEmpty(payCheckUrl)) { _PayCheckUrl = payCheckUrl; } if (! string.IsNullOrEmpty(getTokenUrl)) { _GetTokenUrl = getTokenUrl; } TraceLog.Trace("HuaweiPaySvc.Init clientId {0} clientSecret {1} payUrl {2} tokenUrl {3}" , ClientId, ClientSecret, _PayCheckUrl, _GetTokenUrl); } public static string GetAppAccessToken() { var allParams = new Dictionary(); allParams["client_id"] = ClientId; allParams["client_secret"] = ClientSecret; allParams["grant_type"] = "client_credentials"; var content = new FormUrlEncodedContent(allParams); string ret = HttpUtils.HttpPost(_GetTokenUrl, content, out bool exception); if (ret == null) { TraceLog.Error("HuaweiPaySvc.GetAppAccessToken HttpPost failed"); return null; } TraceLog.Trace("HuaweiPaySvc.GetAppAccessToken ret {0}", ret); JsonData jsonData = JsonMapper.ToObject(ret); JsonData tokenData = jsonData["access_token"]; if (tokenData == null) { TraceLog.Error("HuaweiPaySvc.GetAppAccessToken no access_token"); return null; } return tokenData.ToString(); } private static void FillPayGoogleSuccRes(ref SSPayGoogleSuccessReq req, ref SSPayGoogleSuccessRes res) { res.Uid = req.Uid; res.PayType = req.PayType; res.GmTestPay = req.GmTestPay; res.PayParam1 = req.PayParam1; res.PayParam2 = req.PayParam2; res.ItemID = req.ItemID; res.OrderId.SetString(req.OrderId.GetPtr()); res.OrderId3rd.SetString(req.OrderId3rd.GetPtr()); res.Currency.SetString(req.Currency.GetPtr()); } // 客户端通知服务器支付成功 public static void OnCltPayGoogleSuccReq(uint remoteAppID, StructPacket packet) { ref var req = ref packet.GetMessage(); string publicKeyBase64 = HttpProxyPayServerUtils.GetServerConfig().huaweiPayPublicKey; if (string.IsNullOrEmpty(publicKeyBase64)) { publicKeyBase64 = PayPublicKey; } string purchaseData = req.PurchaseData.GetString(); string signature = req.Signature.GetString(); // 校验签名 bool ret = HuaweiPaySecurity.VerifyRsaSign(purchaseData, signature, publicKeyBase64, HuaweiPaySignatureType.SHA256WithRSA); if (ret == false) { TraceLog.Error("HuaweiPaySvc.OnCltPayGoogleSuccReq uid {0} sign check failed", req.Uid); return; } string orderId = req.OrderId.GetString(); if (string.IsNullOrEmpty(orderId)) { TraceLog.Error("HuaweiPaySvc.OnCltPayGoogleSuccReq uid {0} orderId is null", req.Uid); return; } // 分发到线程池到华为服务器校验PayToken int idx = (int)(HashHelper.HashStringForIndex(orderId) % HttpProxyPayServerUtils.HttpWorkThreadCount); TraceLog.Debug("HuaweiPaySvc.OnCltPayGoogleSuccReq uid {0} distribute to task {1}", req.Uid, idx); MessageTaskDistributor.Instance.Distribute(remoteAppID, packet, idx); } public static int HttpPostCheckPayTokenInner(string payToken, string productId, out JsonData payDetail) { // payToken校验成功时, response中可以获取到华为服务器返回的支付详情 payDetail = null; var svrData = HttpProxyPayServerUtils.GetHttpProxyServerData(); if (svrData.huaweiAppAccessToken == null) { svrData.huaweiAppAccessToken = GetAppAccessToken(); } if (svrData.huaweiAppAccessToken == null) { return -1; } string oriString = $"APPAT:{svrData.huaweiAppAccessToken}"; string authString = Convert.ToBase64String(Encoding.UTF8.GetBytes(oriString)); Dictionary httpHeaders = new Dictionary(); httpHeaders.Add("Authorization", $"Basic {authString}"); try { Dictionary bodyMap = new Dictionary(); bodyMap.Add("purchaseToken", payToken); bodyMap.Add("productId", productId); var bodyString = JsonSerializer.Serialize(bodyMap); var httpContent = new StringContent(bodyString, Encoding.UTF8, "application/json"); string httpRet = HttpUtils.HttpPost(_PayCheckUrl, httpContent, httpHeaders, 10, out int statusCode); TraceLog.Debug("HuaweiPaySvc.HttpPostCheckPayToken HttpPost res status code {0}", statusCode); // 没有权限表示token过期, 需要重新申请 if (statusCode == 401) { TraceLog.Error("HuaweiPaySvc.HttpPostCheckPayToken HttpPost res status code {0}", statusCode); return statusCode; } if (httpRet == null) { TraceLog.Error("HuaweiPaySvc.HttpPostCheckPayToken HttpPost return null"); return -1; } JsonData jsonData = JsonMapper.ToObject(httpRet); if (! jsonData.ContainsKey("responseCode")) { TraceLog.Error("HuaweiPaySvc.HttpPostCheckPayToken no [responseCode]"); return -1; } string codeStr = jsonData["responseCode"].ToString(); if (! int.TryParse(codeStr, out int resCode)) { TraceLog.Error("HuaweiPaySvc.HttpPostCheckPayToken invalid responseCode {0}", codeStr); resCode = -1; } TraceLog.Trace("HuaweiPaySvc.HttpPostCheckPayToken HttpPost responseCode {0}", resCode); if (resCode == 0) { payDetail = JsonMapper.ToObject(jsonData["purchaseTokenData"].ToString()); } return resCode; } catch (Exception ex) { TraceLog.Exception(ex); } return -1; } } }