| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- <?php
- namespace App\Module\OpenAPI\Validators;
- use UCore\Validator;
- /**
- * API验证器
- *
- * 用于验证API相关的数据
- */
- class ApiValidator extends Validator
- {
- /**
- * 验证API密钥格式
- *
- * @param string $apiKey
- * @param string $arg
- * @return void
- */
- public function validateApiKey(string $apiKey, string $arg): void
- {
- if (empty($apiKey)) {
- $this->addError($arg, 'API密钥不能为空');
- return;
- }
- // 检查API密钥格式(app_id:app_secret)
- if (!str_contains($apiKey, ':')) {
- $this->addError($arg, 'API密钥格式错误,应为 app_id:app_secret 格式');
- return;
- }
- $parts = explode(':', $apiKey, 2);
- if (count($parts) !== 2) {
- $this->addError($arg, 'API密钥格式错误');
- return;
- }
- [$appId, $appSecret] = $parts;
- if (empty($appId) || empty($appSecret)) {
- $this->addError($arg, 'API密钥的应用ID和密钥都不能为空');
- return;
- }
- // 验证应用ID格式(32位字符)
- if (strlen($appId) !== 32 || !ctype_alnum($appId)) {
- $this->addError($arg, '应用ID格式错误');
- return;
- }
- // 验证应用密钥格式(64位字符)
- if (strlen($appSecret) !== 64 || !ctype_alnum($appSecret)) {
- $this->addError($arg, '应用密钥格式错误');
- return;
- }
- }
- /**
- * 验证JWT令牌格式
- *
- * @param string $token
- * @param string $arg
- * @return void
- */
- public function validateJwtToken(string $token, string $arg): void
- {
- if (empty($token)) {
- $this->addError($arg, 'JWT令牌不能为空');
- return;
- }
- // JWT令牌应该有3个部分,用.分隔
- $parts = explode('.', $token);
- if (count($parts) !== 3) {
- $this->addError($arg, 'JWT令牌格式错误');
- return;
- }
- // 验证每个部分都是有效的base64编码
- foreach ($parts as $index => $part) {
- if (empty($part)) {
- $this->addError($arg, 'JWT令牌格式错误');
- return;
- }
- // 尝试base64解码
- $decoded = base64_decode($part, true);
- if ($decoded === false) {
- $this->addError($arg, 'JWT令牌格式错误');
- return;
- }
- }
- }
- /**
- * 验证签名参数
- *
- * @param array $params
- * @param string $arg
- * @return void
- */
- public function validateSignatureParams(array $params, string $arg): void
- {
- $requiredParams = ['timestamp', 'nonce', 'signature'];
- foreach ($requiredParams as $param) {
- if (!isset($params[$param]) || empty($params[$param])) {
- $this->addError($arg, "缺少必需的签名参数: {$param}");
- return;
- }
- }
- // 验证时间戳
- $timestamp = $params['timestamp'];
- if (!is_numeric($timestamp)) {
- $this->addError($arg, '时间戳格式错误');
- return;
- }
- // 检查时间戳是否在合理范围内(5分钟内)
- $currentTime = time();
- $timeDiff = abs($currentTime - $timestamp);
- if ($timeDiff > 300) { // 5分钟
- $this->addError($arg, '请求时间戳过期');
- return;
- }
- // 验证随机数
- $nonce = $params['nonce'];
- if (strlen($nonce) < 8) {
- $this->addError($arg, '随机数长度不足');
- return;
- }
- // 验证签名格式
- $signature = $params['signature'];
- if (strlen($signature) !== 64 || !ctype_xdigit($signature)) {
- $this->addError($arg, '签名格式错误');
- return;
- }
- }
- /**
- * 验证IP地址格式
- *
- * @param string $ip
- * @param string $arg
- * @return void
- */
- public function validateIpAddress(string $ip, string $arg): void
- {
- if (empty($ip)) {
- $this->addError($arg, 'IP地址不能为空');
- return;
- }
- // 验证IPv4或IPv6地址
- if (!filter_var($ip, FILTER_VALIDATE_IP)) {
- $this->addError($arg, 'IP地址格式错误');
- return;
- }
- }
- /**
- * 验证IP白名单格式
- *
- * @param array $ipList
- * @param string $arg
- * @return void
- */
- public function validateIpWhitelist(array $ipList, string $arg): void
- {
- if (empty($ipList)) {
- $this->addError($arg, 'IP白名单不能为空');
- return;
- }
- foreach ($ipList as $index => $ip) {
- if (empty($ip)) {
- $this->addError($arg, "第" . ($index + 1) . "个IP地址不能为空");
- continue;
- }
- // 支持CIDR格式
- if (str_contains($ip, '/')) {
- if (!$this->validateCidr($ip)) {
- $this->addError($arg, "第" . ($index + 1) . "个IP地址CIDR格式错误: {$ip}");
- }
- } else {
- // 支持通配符
- if (str_contains($ip, '*')) {
- if (!$this->validateWildcardIp($ip)) {
- $this->addError($arg, "第" . ($index + 1) . "个IP地址通配符格式错误: {$ip}");
- }
- } else {
- // 普通IP地址
- if (!filter_var($ip, FILTER_VALIDATE_IP)) {
- $this->addError($arg, "第" . ($index + 1) . "个IP地址格式错误: {$ip}");
- }
- }
- }
- }
- }
- /**
- * 验证CIDR格式
- *
- * @param string $cidr
- * @return bool
- */
- protected function validateCidr(string $cidr): bool
- {
- $parts = explode('/', $cidr);
- if (count($parts) !== 2) {
- return false;
- }
- [$ip, $mask] = $parts;
- // 验证IP地址
- if (!filter_var($ip, FILTER_VALIDATE_IP)) {
- return false;
- }
- // 验证子网掩码
- if (!is_numeric($mask)) {
- return false;
- }
- $mask = (int)$mask;
- if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
- // IPv4
- return $mask >= 0 && $mask <= 32;
- } else {
- // IPv6
- return $mask >= 0 && $mask <= 128;
- }
- }
- /**
- * 验证通配符IP格式
- *
- * @param string $ip
- * @return bool
- */
- protected function validateWildcardIp(string $ip): bool
- {
- // 将*替换为0进行验证
- $testIp = str_replace('*', '0', $ip);
- return filter_var($testIp, FILTER_VALIDATE_IP) !== false;
- }
- /**
- * 验证频率限制配置
- *
- * @param array $rateLimits
- * @param string $arg
- * @return void
- */
- public function validateRateLimits(array $rateLimits, string $arg): void
- {
- $validTypes = [
- 'requests_per_minute',
- 'requests_per_hour',
- 'requests_per_day',
- 'requests_per_week',
- 'requests_per_month'
- ];
- foreach ($rateLimits as $type => $limit) {
- if (!in_array($type, $validTypes)) {
- $this->addError($arg, "无效的限制类型: {$type}");
- continue;
- }
- if (!is_numeric($limit) || $limit < 0) {
- $this->addError($arg, "限制值必须是非负数: {$type}");
- continue;
- }
- // 检查限制值的合理性
- $maxLimits = [
- 'requests_per_minute' => 1000,
- 'requests_per_hour' => 10000,
- 'requests_per_day' => 100000,
- 'requests_per_week' => 500000,
- 'requests_per_month' => 2000000,
- ];
- if ($limit > $maxLimits[$type]) {
- $this->addError($arg, "限制值过大: {$type} 最大值为 {$maxLimits[$type]}");
- }
- }
- }
- /**
- * 验证权限范围
- *
- * @param array $scopes
- * @param string $arg
- * @return void
- */
- public function validateScopes(array $scopes, string $arg): void
- {
- if (empty($scopes)) {
- $this->addError($arg, '权限范围不能为空');
- return;
- }
- $validScopes = [
- 'USER_READ', 'USER_WRITE',
- 'GAME_READ', 'GAME_WRITE',
- 'ITEM_READ', 'ITEM_WRITE',
- 'FUND_READ', 'FUND_WRITE',
- 'TRADE_READ', 'TRADE_WRITE',
- 'ADMIN_READ', 'ADMIN_WRITE',
- 'SYSTEM_READ', 'SYSTEM_WRITE',
- 'NOTIFICATION_READ', 'NOTIFICATION_WRITE',
- 'LOG_READ',
- '*', 'ADMIN'
- ];
- foreach ($scopes as $scope) {
- if (!in_array($scope, $validScopes)) {
- $this->addError($arg, "无效的权限范围: {$scope}");
- }
- }
- }
- }
|