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
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;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|