更新
This commit is contained in:
@@ -34,10 +34,12 @@ LOG_LEVEL=Information
|
||||
# WECHATPAY__APPID=wx1234567890abcdef
|
||||
# WECHATPAY__MERCHANTID=1900000001
|
||||
# WECHATPAY__CERTIFICATESERIALNUMBER=7777777777777777777777777777777777777777
|
||||
# WECHATPAY__PRIVATEKEYPATH=certs/apiclient_key.pem
|
||||
# WECHATPAY__PRIVATEKEYPEM=certs/apiclient_key.pem
|
||||
# WECHATPAY__PRIVATEKEYPATH=
|
||||
# WECHATPAY__NOTIFYURL=https://your-domain.example.com/api/payments/wechat/notify
|
||||
# WECHATPAY__APIV3KEY=32bytesapiv3keyxxxxxxxxxxxxxxxx
|
||||
# WECHATPAY__PLATFORMPUBLICKEYPATH=certs/wechatpay_public_key.pem
|
||||
# WECHATPAY__PLATFORMPUBLICKEYPEM=certs/wechatpay_public_key.pem
|
||||
# WECHATPAY__PLATFORMPUBLICKEYPATH=
|
||||
# WECHATPAY__PLATFORMPUBLICKEYSERIAL=PUB_KEY_ID_xxxxxxxxxxxxxxxxxxxxxxxx
|
||||
# WECHATPAY__CURRENCY=CNY
|
||||
# WECHATPAY__ORDEREXPIREMINUTES=5
|
||||
|
||||
@@ -273,28 +273,10 @@ public sealed class WeChatPayService
|
||||
|
||||
private string GetPrivateKeyPem()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_options.PrivateKeyPem))
|
||||
{
|
||||
return _options.PrivateKeyPem;
|
||||
}
|
||||
|
||||
var keyPath = _options.PrivateKeyPath;
|
||||
if (string.IsNullOrWhiteSpace(keyPath))
|
||||
{
|
||||
throw new InvalidOperationException("WeChat private key is not configured.");
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(keyPath))
|
||||
{
|
||||
keyPath = Path.Combine(AppContext.BaseDirectory, keyPath);
|
||||
}
|
||||
|
||||
if (!File.Exists(keyPath))
|
||||
{
|
||||
throw new InvalidOperationException($"WeChat private key file was not found: {keyPath}");
|
||||
}
|
||||
|
||||
return File.ReadAllText(keyPath);
|
||||
return ResolvePemContent(
|
||||
_options.PrivateKeyPem,
|
||||
_options.PrivateKeyPath,
|
||||
"WeChat private key");
|
||||
}
|
||||
|
||||
private void ValidateOptions()
|
||||
@@ -320,10 +302,14 @@ public sealed class WeChatPayService
|
||||
{
|
||||
missingFields.Add("WeChatPay:NotifyUrl");
|
||||
}
|
||||
else
|
||||
{
|
||||
ValidateNotifyUrl(_options.NotifyUrl);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_options.PrivateKeyPem) && string.IsNullOrWhiteSpace(_options.PrivateKeyPath))
|
||||
{
|
||||
missingFields.Add("WeChatPay:PrivateKeyPath or WeChatPay:PrivateKeyPem");
|
||||
missingFields.Add("WeChatPay:PrivateKeyPem (PEM content or file path)");
|
||||
}
|
||||
|
||||
if (missingFields.Count > 0)
|
||||
@@ -341,11 +327,15 @@ public sealed class WeChatPayService
|
||||
{
|
||||
missingFields.Add("WeChatPay:ApiV3Key");
|
||||
}
|
||||
else
|
||||
{
|
||||
ValidateApiV3Key(_options.ApiV3Key);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_options.PlatformPublicKeyPem) &&
|
||||
string.IsNullOrWhiteSpace(_options.PlatformPublicKeyPath))
|
||||
{
|
||||
missingFields.Add("WeChatPay:PlatformPublicKeyPath or WeChatPay:PlatformPublicKeyPem");
|
||||
missingFields.Add("WeChatPay:PlatformPublicKeyPem (PEM content or file path)");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_options.PlatformPublicKeySerial))
|
||||
@@ -392,28 +382,74 @@ public sealed class WeChatPayService
|
||||
|
||||
private string GetPlatformPublicKeyPem()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(_options.PlatformPublicKeyPem))
|
||||
return ResolvePemContent(
|
||||
_options.PlatformPublicKeyPem,
|
||||
_options.PlatformPublicKeyPath,
|
||||
"WeChat platform public key");
|
||||
}
|
||||
|
||||
private static string ResolvePemContent(string pemOrPath, string fallbackPath, string keyName)
|
||||
{
|
||||
var configuredValue = !string.IsNullOrWhiteSpace(pemOrPath)
|
||||
? pemOrPath.Trim()
|
||||
: fallbackPath.Trim();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(configuredValue))
|
||||
{
|
||||
return _options.PlatformPublicKeyPem;
|
||||
throw new InvalidOperationException($"{keyName} is not configured.");
|
||||
}
|
||||
|
||||
var keyPath = _options.PlatformPublicKeyPath;
|
||||
if (string.IsNullOrWhiteSpace(keyPath))
|
||||
if (LooksLikePemContent(configuredValue))
|
||||
{
|
||||
throw new InvalidOperationException("WeChat platform public key is not configured.");
|
||||
return configuredValue;
|
||||
}
|
||||
|
||||
if (!Path.IsPathRooted(keyPath))
|
||||
var resolvedPath = configuredValue;
|
||||
if (!Path.IsPathRooted(resolvedPath))
|
||||
{
|
||||
keyPath = Path.Combine(AppContext.BaseDirectory, keyPath);
|
||||
resolvedPath = Path.Combine(AppContext.BaseDirectory, resolvedPath);
|
||||
}
|
||||
|
||||
if (!File.Exists(keyPath))
|
||||
if (!File.Exists(resolvedPath))
|
||||
{
|
||||
throw new InvalidOperationException($"WeChat platform public key file was not found: {keyPath}");
|
||||
throw new InvalidOperationException($"{keyName} file was not found: {resolvedPath}");
|
||||
}
|
||||
|
||||
return File.ReadAllText(keyPath);
|
||||
return File.ReadAllText(resolvedPath);
|
||||
}
|
||||
|
||||
private static bool LooksLikePemContent(string value)
|
||||
{
|
||||
return value.Contains("-----BEGIN", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static void ValidateNotifyUrl(string notifyUrl)
|
||||
{
|
||||
if (!Uri.TryCreate(notifyUrl, UriKind.Absolute, out var uri))
|
||||
{
|
||||
throw new InvalidOperationException("WeChatPay:NotifyUrl must be a valid absolute URL.");
|
||||
}
|
||||
|
||||
var isLocalhost = uri.Host.Equals("localhost", StringComparison.OrdinalIgnoreCase) ||
|
||||
uri.Host.Equals("127.0.0.1", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
if (!isLocalhost && !uri.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException("WeChatPay:NotifyUrl should use https for public callback addresses.");
|
||||
}
|
||||
}
|
||||
|
||||
private static void ValidateApiV3Key(string apiV3Key)
|
||||
{
|
||||
if (LooksLikePemContent(apiV3Key) || apiV3Key.StartsWith("MII", StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException("WeChatPay:ApiV3Key looks like a certificate or private key. It must be the 32-byte APIv3 key from WeChat Pay.");
|
||||
}
|
||||
|
||||
if (Encoding.UTF8.GetByteCount(apiV3Key) != 32)
|
||||
{
|
||||
throw new InvalidOperationException("WeChatPay:ApiV3Key must be exactly 32 bytes.");
|
||||
}
|
||||
}
|
||||
|
||||
private string DecryptNotificationResource(PaymentNotificationResource resource)
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
"AppId": "wxa27a3e3cfce7ae19",
|
||||
"MerchantId": "1107066208",
|
||||
"CertificateSerialNumber": "3243AE8427384A692FBAA92C5EC5887BEF1988FD",
|
||||
"PrivateKeyPath": "/etc/ssl/certs/apiclient_key.pem",
|
||||
"PrivateKeyPem": "",
|
||||
"PrivateKeyPath": "",
|
||||
"PrivateKeyPem": "/etc/ssl/certs/apiclient_key.pem",
|
||||
"NotifyUrl": "http://csicsizn.com:8080/api/payments/wechat/notify",
|
||||
"ApiV3Key": "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDMlj1LkO9Cfg3LWBYpe9GBn7vWgLE6kqEG1ohaxbaPxA6OwuGn0XQZfRBbJmncSXGLYahQ7T0OvFBIp8SyYm6q9kol8c9naxd+KxjMrx/qSWqwEJ76meBNK6LBYBVFTobg47cexpyR1TOZK0EFBGJQU2yQ1nsuQczVvq+WaSn4+kVENWf+o2g2nFS1VXNBIjL0/C8vXbz/0Y8k6ecH5mbmy/t+YR6X4TsiIAzIxIcfMMNhVCwqKLsu3D20N0ViYbKToHWIXi8wS8dyruHqQ1lZVJV/fF7pdI36HFI94enksCZrDb1LVFjL+4ccE04MJLIEZSH73RrOFkLaRzn8pwBbAgMBAAECggEAY7kD7baa+XVKMgkg3F2vVJjQzZDzUpKwjQ27b0uaXl95nRrfNZcCGX59n4CM70SZZRBYJAJP1cP",
|
||||
"PlatformPublicKeyPath": "",
|
||||
|
||||
Reference in New Issue
Block a user