SignatureMiddleware.php 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. <?php
  2. namespace app\common\middleware;
  3. use think\facade\Cache;
  4. use think\Response;
  5. class SignatureMiddleware
  6. {
  7. public function handle($request, \Closure $next)
  8. {
  9. // 1. 获取加密签名
  10. $sign = $request->header('X-Sign');
  11. if (!$sign) {
  12. return $this->reject('缺少签名', 401);
  13. }
  14. // 2. 读取私钥
  15. $privateKey = file_get_contents(env('RSA_PRIVATE_KEY_PATH'));
  16. if (!$privateKey) {
  17. return $this->reject('服务器密钥错误', 500);
  18. }
  19. // 3. 解密数据
  20. $decrypted = '';
  21. openssl_private_decrypt(base64_decode($sign), $decrypted, $privateKey);
  22. if (!$decrypted || !strpos($decrypted, ':')) {
  23. return $this->reject('无效签名', 403);
  24. }
  25. // 4. 分离随机数和时间戳
  26. list($nonce, $timestamp) = explode(':', $decrypted, 2);
  27. // 5. 验证时间有效性(5分钟内)
  28. if (abs(time() - $timestamp / 1000) > 300) {
  29. return $this->reject('请求已过期', 403);
  30. }
  31. // 6. 防重放攻击(检查nonce唯一性)
  32. $cacheKey = 'nonce_' . $nonce;
  33. if (Cache::has($cacheKey)) {
  34. return $this->reject('重复请求', 403);
  35. }
  36. Cache::set($cacheKey, 1, 300); // 5分钟缓存
  37. return $next($request);
  38. }
  39. private function reject($msg, $code): Response
  40. {
  41. return Response::create([
  42. 'code' => $code,
  43. 'msg' => $msg
  44. ], 'json')->code($code);
  45. }
  46. }