mirror of
https://gitee.com/zoujingli/WeChatDeveloper.git
synced 2026-09-04 15:04:32 +08:00
feat(security): 强化 token 密钥证书格式校验
- 新增 CredentialValidator,集中校验微信 Token、EncodingAESKey、APIv3 Key、RSA 密钥和证书。 - 配置对象构造时提前验证微信、微信支付、支付宝关键凭证格式。 - 消息加解密和支付通知解密复用统一校验,减少运行期隐性错误。 - 补充无效 Token、密钥、证书和解密场景测试,提升凭证错误可诊断性。
This commit is contained in:
parent
80af84bcb9
commit
e8cd998852
@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付宝支付配置对象。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Config;
|
namespace We\Config;
|
||||||
@ -11,6 +13,4 @@ namespace We\Config;
|
|||||||
/**
|
/**
|
||||||
* 支付宝支付配置,继承支付宝开放平台网关签名与验签参数。
|
* 支付宝支付配置,继承支付宝开放平台网关签名与验签参数。
|
||||||
*/
|
*/
|
||||||
final class AlipayPaymentConfig extends AlipayPlatformConfig
|
final class AlipayPaymentConfig extends AlipayPlatformConfig {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付宝开放平台配置对象。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Config;
|
namespace We\Config;
|
||||||
|
|
||||||
use We\Contract\ConfigInterface;
|
use We\Contract\ConfigInterface;
|
||||||
use We\Exception\WechatException;
|
use We\Exception\WechatException;
|
||||||
|
use We\Support\CredentialValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 支付宝开放平台基础配置。
|
* 支付宝开放平台基础配置。
|
||||||
@ -44,6 +47,16 @@ class AlipayPlatformConfig implements ConfigInterface
|
|||||||
if (trim($this->appid) === '' || trim($this->privateKey) === '') {
|
if (trim($this->appid) === '' || trim($this->privateKey) === '') {
|
||||||
throw new WechatException('支付宝 appid 与 private_key 不能为空');
|
throw new WechatException('支付宝 appid 与 private_key 不能为空');
|
||||||
}
|
}
|
||||||
|
if (!in_array(strtoupper($this->signType), ['RSA', 'RSA2'], true)) {
|
||||||
|
throw new WechatException('支付宝 sign_type 仅支持 RSA 或 RSA2');
|
||||||
|
}
|
||||||
|
if (!filter_var($this->gateway, FILTER_VALIDATE_URL)) {
|
||||||
|
throw new WechatException('支付宝 gateway 必须是有效 URL');
|
||||||
|
}
|
||||||
|
CredentialValidator::assertPrivateKey($this->privateKey, '支付宝 private_key', true);
|
||||||
|
if ($this->alipayPublicKey !== '') {
|
||||||
|
CredentialValidator::assertPublicKey($this->alipayPublicKey, '支付宝 alipay_public_key', true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付 APIv3 商户配置对象。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Config;
|
namespace We\Config;
|
||||||
|
|
||||||
use We\Contract\ConfigInterface;
|
use We\Contract\ConfigInterface;
|
||||||
use We\Exception\WechatException;
|
use We\Exception\WechatException;
|
||||||
|
use We\Support\CredentialValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付 APIv3 商户配置。
|
* 微信支付 APIv3 商户配置。
|
||||||
@ -53,6 +56,14 @@ final class WechatPaymentConfig implements ConfigInterface
|
|||||||
throw new WechatException($name . ' 不能为空');
|
throw new WechatException($name . ' 不能为空');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CredentialValidator::assertApiV3Key($this->apiV3Key);
|
||||||
|
CredentialValidator::assertPrivateKey($this->merchantPrivateKey, 'merchantPrivateKey');
|
||||||
|
if ($this->platformCertificate !== '') {
|
||||||
|
CredentialValidator::assertPublicKey($this->platformCertificate, 'platformCertificate');
|
||||||
|
}
|
||||||
|
if ($this->platformPublicKey !== '') {
|
||||||
|
CredentialValidator::assertPublicKey($this->platformPublicKey, 'platformPublicKey');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,7 +73,7 @@ final class WechatPaymentConfig implements ConfigInterface
|
|||||||
*/
|
*/
|
||||||
public static function fromArray(array $data): static
|
public static function fromArray(array $data): static
|
||||||
{
|
{
|
||||||
return new static(
|
return new self(
|
||||||
(string)($data['appid'] ?? ''),
|
(string)($data['appid'] ?? ''),
|
||||||
(string)($data['mch_id'] ?? $data['mchid'] ?? ''),
|
(string)($data['mch_id'] ?? $data['mchid'] ?? ''),
|
||||||
(string)($data['api_v3_key'] ?? $data['mch_v3_key'] ?? ''),
|
(string)($data['api_v3_key'] ?? $data['mch_v3_key'] ?? ''),
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信公众平台配置对象。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Config;
|
namespace We\Config;
|
||||||
|
|
||||||
use We\Contract\ConfigInterface;
|
use We\Contract\ConfigInterface;
|
||||||
use We\Exception\WechatException;
|
use We\Exception\WechatException;
|
||||||
|
use We\Support\CredentialValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信公众平台基础配置。
|
* 微信公众平台基础配置。
|
||||||
@ -42,7 +45,7 @@ final class WechatPlatformConfig implements ConfigInterface
|
|||||||
*/
|
*/
|
||||||
public static function fromArray(array $data): static
|
public static function fromArray(array $data): static
|
||||||
{
|
{
|
||||||
return new static(
|
return new self(
|
||||||
(string)($data['appid'] ?? ''),
|
(string)($data['appid'] ?? ''),
|
||||||
(string)($data['appsecret'] ?? $data['app_secret'] ?? ''),
|
(string)($data['appsecret'] ?? $data['app_secret'] ?? ''),
|
||||||
(string)($data['token'] ?? ''),
|
(string)($data['token'] ?? ''),
|
||||||
@ -64,5 +67,14 @@ final class WechatPlatformConfig implements ConfigInterface
|
|||||||
throw new WechatException($name . ' 不能为空');
|
throw new WechatException($name . ' 不能为空');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($this->token !== '') {
|
||||||
|
CredentialValidator::assertWechatToken($this->token);
|
||||||
|
}
|
||||||
|
if ($this->encodingAesKey !== '') {
|
||||||
|
if (trim($this->token) === '') {
|
||||||
|
throw new WechatException('token 不能为空');
|
||||||
|
}
|
||||||
|
CredentialValidator::assertEncodingAesKey($this->encodingAesKey, 'encodingAesKey');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信服务平台(第三方平台)配置对象。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Config;
|
namespace We\Config;
|
||||||
|
|
||||||
use We\Contract\ConfigInterface;
|
use We\Contract\ConfigInterface;
|
||||||
use We\Exception\WechatException;
|
use We\Exception\WechatException;
|
||||||
|
use We\Support\CredentialValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信服务平台(第三方平台)配置。
|
* 微信服务平台(第三方平台)配置。
|
||||||
@ -47,6 +50,8 @@ final class WechatServiceConfig implements ConfigInterface
|
|||||||
throw new WechatException($name . ' 不能为空');
|
throw new WechatException($name . ' 不能为空');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CredentialValidator::assertWechatToken($this->componentToken, 'componentToken');
|
||||||
|
CredentialValidator::assertEncodingAesKey($this->componentEncodingAesKey, 'componentEncodingAesKey');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,7 +61,7 @@ final class WechatServiceConfig implements ConfigInterface
|
|||||||
*/
|
*/
|
||||||
public static function fromArray(array $data): static
|
public static function fromArray(array $data): static
|
||||||
{
|
{
|
||||||
return new static(
|
return new self(
|
||||||
(string)($data['component_appid'] ?? ''),
|
(string)($data['component_appid'] ?? ''),
|
||||||
(string)($data['component_appsecret'] ?? $data['component_app_secret'] ?? ''),
|
(string)($data['component_appsecret'] ?? $data['component_app_secret'] ?? ''),
|
||||||
(string)($data['component_token'] ?? ''),
|
(string)($data['component_token'] ?? ''),
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信小程序配置对象。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Config;
|
namespace We\Config;
|
||||||
@ -37,7 +39,7 @@ final class WechatWxappConfig implements ConfigInterface
|
|||||||
*/
|
*/
|
||||||
public static function fromArray(array $data): static
|
public static function fromArray(array $data): static
|
||||||
{
|
{
|
||||||
return new static(
|
return new self(
|
||||||
(string)($data['appid'] ?? ''),
|
(string)($data['appid'] ?? ''),
|
||||||
(string)($data['appsecret'] ?? $data['app_secret'] ?? ''),
|
(string)($data['appsecret'] ?? $data['app_secret'] ?? ''),
|
||||||
(string)($data['storage_scope'] ?? $data['storageScope'] ?? ''),
|
(string)($data['storage_scope'] ?? $data['storageScope'] ?? ''),
|
||||||
|
|||||||
107
src/Support/CredentialValidator.php
Normal file
107
src/Support/CredentialValidator.php
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
/**
|
||||||
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace We\Support;
|
||||||
|
|
||||||
|
use We\Exception\WechatException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密钥、证书与平台安全参数校验工具。
|
||||||
|
*/
|
||||||
|
final class CredentialValidator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 校验微信服务器配置 Token。
|
||||||
|
*/
|
||||||
|
public static function assertWechatToken(string $token, string $field = 'token'): void
|
||||||
|
{
|
||||||
|
if (preg_match('/^[A-Za-z0-9]{3,32}$/', $token) !== 1) {
|
||||||
|
throw new WechatException($field . ' 必须是 3-32 位英文或数字');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验微信消息 EncodingAESKey。
|
||||||
|
*/
|
||||||
|
public static function assertEncodingAesKey(string $encodingAesKey, string $field = 'EncodingAESKey'): void
|
||||||
|
{
|
||||||
|
if (strlen($encodingAesKey) !== 43) {
|
||||||
|
throw new WechatException($field . ' 必须是 43 位有效字符串');
|
||||||
|
}
|
||||||
|
$key = base64_decode($encodingAesKey . '=', true);
|
||||||
|
if ($key === false || strlen($key) !== 32) {
|
||||||
|
throw new WechatException($field . ' 必须是 43 位有效字符串');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验微信支付 APIv3 密钥。
|
||||||
|
*/
|
||||||
|
public static function assertApiV3Key(string $apiV3Key): void
|
||||||
|
{
|
||||||
|
if (strlen($apiV3Key) !== 32) {
|
||||||
|
throw new WechatException('apiV3Key 必须是 32 字节字符串');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验 RSA 私钥。
|
||||||
|
*/
|
||||||
|
public static function assertPrivateKey(string $privateKey, string $field, bool $wrapRawKey = false): void
|
||||||
|
{
|
||||||
|
$resource = openssl_pkey_get_private(self::normalizePrivateKey($privateKey, $wrapRawKey));
|
||||||
|
if ($resource === false) {
|
||||||
|
throw new WechatException($field . ' 格式无效');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验 RSA 公钥或证书。
|
||||||
|
*/
|
||||||
|
public static function assertPublicKey(string $publicKey, string $field, bool $wrapRawKey = false): void
|
||||||
|
{
|
||||||
|
$resource = openssl_pkey_get_public(self::normalizePublicKey($publicKey, $wrapRawKey));
|
||||||
|
if ($resource === false) {
|
||||||
|
throw new WechatException($field . ' 格式无效');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将私钥规范化为 PEM 字符串;支付宝支持传入无头尾的密钥正文。
|
||||||
|
*/
|
||||||
|
public static function normalizePrivateKey(string $privateKey, bool $wrapRawKey = false): string
|
||||||
|
{
|
||||||
|
$key = trim($privateKey);
|
||||||
|
if ($key === '' || str_contains($key, 'BEGIN')) {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
if (!$wrapRawKey) {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "-----BEGIN PRIVATE KEY-----\n" . chunk_split($key, 64, "\n") . '-----END PRIVATE KEY-----';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将公钥规范化为 PEM 字符串;支付宝支持传入无头尾的公钥正文。
|
||||||
|
*/
|
||||||
|
public static function normalizePublicKey(string $publicKey, bool $wrapRawKey = false): string
|
||||||
|
{
|
||||||
|
$key = trim($publicKey);
|
||||||
|
if ($key === '' || str_contains($key, 'BEGIN')) {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
if (!$wrapRawKey) {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "-----BEGIN PUBLIC KEY-----\n" . chunk_split($key, 64, "\n") . '-----END PUBLIC KEY-----';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信消息安全模式加解密工具。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Support;
|
namespace We\Support;
|
||||||
@ -28,11 +30,10 @@ final class MessageCrypto
|
|||||||
string $encodingAesKey,
|
string $encodingAesKey,
|
||||||
private string $appid,
|
private string $appid,
|
||||||
) {
|
) {
|
||||||
if (strlen($encodingAesKey) !== 43) {
|
CredentialValidator::assertWechatToken($this->token);
|
||||||
throw new WechatException('EncodingAESKey 必须是 43 位有效字符串');
|
CredentialValidator::assertEncodingAesKey($encodingAesKey);
|
||||||
}
|
|
||||||
$key = base64_decode($encodingAesKey . '=', true);
|
$key = base64_decode($encodingAesKey . '=', true);
|
||||||
if ($key === false || strlen($key) !== 32) {
|
if (!is_string($key)) {
|
||||||
throw new WechatException('EncodingAESKey 必须是 43 位有效字符串');
|
throw new WechatException('EncodingAESKey 必须是 43 位有效字符串');
|
||||||
}
|
}
|
||||||
$this->aesKey = $key;
|
$this->aesKey = $key;
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付 APIv3 通知资源解密工具。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Support;
|
namespace We\Support;
|
||||||
@ -20,17 +22,25 @@ final class PaymentCrypto
|
|||||||
/**
|
/**
|
||||||
* 解密微信支付 APIv3 通知中的 resource 字段。
|
* 解密微信支付 APIv3 通知中的 resource 字段。
|
||||||
*
|
*
|
||||||
* @param array{ciphertext:string,nonce:string,associated_data?:string} $resource
|
* @param array<string,mixed> $resource
|
||||||
* @return array<string,mixed>
|
* @return array<string,mixed>
|
||||||
*/
|
*/
|
||||||
public static function decryptResource(string $apiV3Key, array $resource): array
|
public static function decryptResource(string $apiV3Key, array $resource): array
|
||||||
{
|
{
|
||||||
foreach (['ciphertext', 'nonce'] as $field) {
|
CredentialValidator::assertApiV3Key($apiV3Key);
|
||||||
if (!isset($resource[$field]) || !is_string($resource[$field]) || $resource[$field] === '') {
|
$ciphertextValue = $resource['ciphertext'] ?? null;
|
||||||
throw new WechatException('微信支付回调资源字段缺失: ' . $field);
|
$nonce = $resource['nonce'] ?? null;
|
||||||
}
|
$associatedData = $resource['associated_data'] ?? '';
|
||||||
|
if (!is_string($ciphertextValue) || $ciphertextValue === '') {
|
||||||
|
throw new WechatException('微信支付回调资源字段缺失: ciphertext');
|
||||||
}
|
}
|
||||||
$ciphertext = base64_decode($resource['ciphertext'], true);
|
if (!is_string($nonce) || $nonce === '') {
|
||||||
|
throw new WechatException('微信支付回调资源字段缺失: nonce');
|
||||||
|
}
|
||||||
|
if (!is_string($associatedData)) {
|
||||||
|
throw new WechatException('微信支付回调资源字段无效: associated_data');
|
||||||
|
}
|
||||||
|
$ciphertext = base64_decode($ciphertextValue, true);
|
||||||
if ($ciphertext === false || strlen($ciphertext) <= 16) {
|
if ($ciphertext === false || strlen($ciphertext) <= 16) {
|
||||||
throw new WechatException('微信支付回调密文无效');
|
throw new WechatException('微信支付回调密文无效');
|
||||||
}
|
}
|
||||||
@ -42,9 +52,9 @@ final class PaymentCrypto
|
|||||||
'aes-256-gcm',
|
'aes-256-gcm',
|
||||||
$apiV3Key,
|
$apiV3Key,
|
||||||
OPENSSL_RAW_DATA,
|
OPENSSL_RAW_DATA,
|
||||||
$resource['nonce'],
|
$nonce,
|
||||||
$tag,
|
$tag,
|
||||||
(string)($resource['associated_data'] ?? '')
|
$associatedData
|
||||||
);
|
);
|
||||||
if (!is_string($plain) || $plain === '') {
|
if (!is_string($plain) || $plain === '') {
|
||||||
throw new WechatException('微信支付回调解密失败');
|
throw new WechatException('微信支付回调解密失败');
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 签名与验签工具。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Support;
|
namespace We\Support;
|
||||||
@ -67,7 +69,11 @@ final class Signature
|
|||||||
if ($key === false) {
|
if ($key === false) {
|
||||||
throw new SignatureException('微信支付平台公钥或证书无效');
|
throw new SignatureException('微信支付平台公钥或证书无效');
|
||||||
}
|
}
|
||||||
|
$decoded = base64_decode($signature, true);
|
||||||
|
if ($decoded === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return openssl_verify($message, base64_decode($signature, true) ?: '', $key, OPENSSL_ALGO_SHA256) === 1;
|
return openssl_verify($message, $decoded, $key, OPENSSL_ALGO_SHA256) === 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 平台配置契约与配置对象测试。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Tests;
|
namespace We\Tests;
|
||||||
@ -21,6 +23,7 @@ use We\Exception\WechatException;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 平台配置契约与配置对象测试用例。
|
* 平台配置契约与配置对象测试用例。
|
||||||
|
* @internal
|
||||||
*/
|
*/
|
||||||
#[CoversClass(ConfigInterface::class)]
|
#[CoversClass(ConfigInterface::class)]
|
||||||
final class ConfigInterfaceTest extends TestCase
|
final class ConfigInterfaceTest extends TestCase
|
||||||
@ -33,10 +36,10 @@ final class ConfigInterfaceTest extends TestCase
|
|||||||
foreach ([
|
foreach ([
|
||||||
new WechatPlatformConfig('wx_app', 'secret'),
|
new WechatPlatformConfig('wx_app', 'secret'),
|
||||||
new WechatWxappConfig('wx_wxapp', 'secret'),
|
new WechatWxappConfig('wx_wxapp', 'secret'),
|
||||||
new WechatServiceConfig('wx_component', 'secret', 'token', 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG'),
|
new WechatServiceConfig('wx_component', 'secret', 'token', TestKeys::encodingAesKey()),
|
||||||
new WechatPaymentConfig('wx_app', 'mch', str_repeat('k', 32), 'serial', 'private-key'),
|
new WechatPaymentConfig('wx_app', 'mch', str_repeat('k', 32), 'serial', TestKeys::privateKey()),
|
||||||
new AlipayPlatformConfig('ali_app', 'private-key'),
|
new AlipayPlatformConfig('ali_app', TestKeys::privateKey()),
|
||||||
new AlipayPaymentConfig('ali_pay', 'private-key'),
|
new AlipayPaymentConfig('ali_pay', TestKeys::privateKey()),
|
||||||
] as $config) {
|
] as $config) {
|
||||||
$this->assertInstanceOf(ConfigInterface::class, $config);
|
$this->assertInstanceOf(ConfigInterface::class, $config);
|
||||||
}
|
}
|
||||||
@ -64,6 +67,39 @@ final class ConfigInterfaceTest extends TestCase
|
|||||||
WechatPaymentConfig::fromArray(['appid' => 'wx_app']);
|
WechatPaymentConfig::fromArray(['appid' => 'wx_app']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试微信服务平台配置会校验 EncodingAESKey 格式。
|
||||||
|
*/
|
||||||
|
public function testWechatServiceConfigRejectsInvalidEncodingAesKey(): void
|
||||||
|
{
|
||||||
|
$this->expectException(WechatException::class);
|
||||||
|
$this->expectExceptionMessage('componentEncodingAesKey');
|
||||||
|
|
||||||
|
new WechatServiceConfig('wx_component', 'secret', 'token', 'invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试微信消息 Token 只能使用官方允许的英文或数字格式。
|
||||||
|
*/
|
||||||
|
public function testWechatConfigRejectsInvalidMessageToken(): void
|
||||||
|
{
|
||||||
|
$this->expectException(WechatException::class);
|
||||||
|
$this->expectExceptionMessage('token');
|
||||||
|
|
||||||
|
new WechatPlatformConfig('wx_app', 'secret', 'message_token', TestKeys::encodingAesKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试微信支付配置会校验 APIv3 Key 与商户私钥格式。
|
||||||
|
*/
|
||||||
|
public function testWechatPaymentConfigRejectsInvalidCryptoMaterial(): void
|
||||||
|
{
|
||||||
|
$this->expectException(WechatException::class);
|
||||||
|
$this->expectExceptionMessage('merchantPrivateKey');
|
||||||
|
|
||||||
|
new WechatPaymentConfig('wx_app', 'mch', str_repeat('k', 32), 'serial', 'invalid-private-key');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 测试支付宝支付配置 fromArray 返回子类实例。
|
* 测试支付宝支付配置 fromArray 返回子类实例。
|
||||||
*/
|
*/
|
||||||
@ -71,7 +107,7 @@ final class ConfigInterfaceTest extends TestCase
|
|||||||
{
|
{
|
||||||
$config = AlipayPaymentConfig::fromArray([
|
$config = AlipayPaymentConfig::fromArray([
|
||||||
'appid' => 'ali_pay',
|
'appid' => 'ali_pay',
|
||||||
'private_key' => 'private-key',
|
'private_key' => TestKeys::privateKey(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertInstanceOf(AlipayPaymentConfig::class, $config);
|
$this->assertInstanceOf(AlipayPaymentConfig::class, $config);
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信消息安全模式加解密测试。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Tests;
|
namespace We\Tests;
|
||||||
@ -17,6 +19,7 @@ use We\Support\Signature;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信消息安全模式加解密测试用例。
|
* 微信消息安全模式加解密测试用例。
|
||||||
|
* @internal
|
||||||
*/
|
*/
|
||||||
#[CoversClass(MessageCrypto::class)]
|
#[CoversClass(MessageCrypto::class)]
|
||||||
final class MessageCryptoTest extends TestCase
|
final class MessageCryptoTest extends TestCase
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
declare(strict_types=1);
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付 APIv3 通知 resource 解密测试。
|
* This file is part of HyperfAdmin.
|
||||||
|
*
|
||||||
|
* @Link https://thinkadmin.top
|
||||||
|
* @Author Anyon<zoujingli@qq.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace We\Tests;
|
namespace We\Tests;
|
||||||
@ -14,6 +16,7 @@ use We\Support\PaymentCrypto;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信支付 APIv3 通知 resource 解密测试用例。
|
* 微信支付 APIv3 通知 resource 解密测试用例。
|
||||||
|
* @internal
|
||||||
*/
|
*/
|
||||||
#[CoversClass(PaymentCrypto::class)]
|
#[CoversClass(PaymentCrypto::class)]
|
||||||
final class PaymentCryptoTest extends TestCase
|
final class PaymentCryptoTest extends TestCase
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user