You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
8.3 KiB

1 month ago
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<string, string>();
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<SSPayGoogleSuccessReq>();
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<string, string> httpHeaders = new Dictionary<string, string>();
httpHeaders.Add("Authorization", $"Basic {authString}");
try
{
Dictionary<string, string> bodyMap = new Dictionary<string, string>();
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;
}
}
}