only(['timestamp', 'nonce', 'signature']); // 验证必要参数 if (count(array_filter($essential)) !== 3) { return $this->errorResponse('参数不完整', 400); } // 验证时间戳(5分钟内有效) if (abs(time() - (int)$essential['timestamp']) > 300) { return $this->errorResponse('请求已过期', 400); } // 验证nonce唯一性 $nonceKey = 'nonce:' . $essential['nonce']; if (Cache::has($nonceKey)) { return $this->errorResponse('重复请求', 400); } // 构造签名数据(与前端完全一致) $signData = $request->param(); unset($signData['signature']); // 按键名排序 ksort($signData); // 生成签名字符串(与前端相同格式) $signContent = ''; foreach ($signData as $key => $value) { $signContent .= "{$key}={$value}&"; } $signContent = rtrim($signContent, '&'); // 记录原始签名内容(用于调试) Log::debug("Sign Content: " . $signContent); // 获取公钥 $publicKey = openssl_pkey_get_public( file_get_contents(env('RSA_PUBLIC_KEY_PATH')) ); if (!$publicKey) { Log::error("公钥加载失败"); return $this->errorResponse('系统错误', 500); } // 计算签名的MD5值(与前端一致) $md5Hash = md5($signContent); Log::debug("MD5 Hash: " . $md5Hash); // 解码前端签名(前端使用公钥加密) $signature = base64_decode($essential['signature']); // 使用公钥解密签名 $decrypted = ''; $success = openssl_public_decrypt($signature, $decrypted, $publicKey); if (!$success) { Log::error("签名解密失败: " . openssl_error_string()); return $this->errorResponse('签名验证失败', 403); } Log::debug("解密结果: " . $decrypted); // 比较解密后的值与MD5哈希 if ($decrypted !== $md5Hash) { Log::error("签名验证失败: 期望 {$md5Hash}, 实际 {$decrypted}"); return $this->errorResponse('签名验证失败', 403); } // 记录已使用的nonce(5分钟过期) Cache::set($nonceKey, 1, 300); return $next($request); } private function errorResponse(string $message, int $code): Response { return json([ 'code' => $code, 'msg' => $message, 'data' => null ])->code($code); } }