ApiAgent.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\Middleware;
  4. use App\Master\Enum\RedisKeyEnum;
  5. use App\Model\Arts\UserModel;
  6. use App\Service\SystemService;
  7. use App\Utils\AppResult;
  8. use App\Utils\Control\ActionUtil;
  9. use App\Utils\Control\AuthUser;
  10. use App\Utils\Encrypt\Token;
  11. use App\Utils\Encrypt\TokenUtil;
  12. use App\Utils\LogUtil;
  13. use App\Utils\RedisUtil;
  14. use Hyperf\Coroutine\Coroutine;
  15. use Hyperf\HttpServer\Contract\RequestInterface;
  16. use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
  17. use Hyperf\HttpServer\Router\Dispatched;
  18. use Psr\Container\ContainerInterface;
  19. use Psr\Http\Message\ResponseInterface;
  20. use Psr\Http\Message\ServerRequestInterface;
  21. use Psr\Http\Server\MiddlewareInterface;
  22. use Psr\Http\Server\RequestHandlerInterface;
  23. class ApiAgent implements MiddlewareInterface
  24. {
  25. // 日志模块名称
  26. const LOG_MODULE = 'ApiAgent-Middleware-Log';
  27. const LOG_ACTION = 'verifyToken';
  28. const PROJECT = 'Api';
  29. /**
  30. * @var ContainerInterface
  31. */
  32. protected $container;
  33. /**
  34. * @var RequestInterface
  35. */
  36. protected $request;
  37. /**
  38. * @var HttpResponse
  39. */
  40. protected $response;
  41. protected $action;
  42. public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
  43. {
  44. $this->container = $container;
  45. $this->response = $response;
  46. $this->request = $request;
  47. }
  48. public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
  49. {
  50. //日志统一写入
  51. LogUtil::getInstance(self::PROJECT . "/");//设置日志存入通道
  52. Coroutine::defer(function () {
  53. LogUtil::close();// 协程结束后统一写入
  54. });
  55. $this->action = $action = ActionUtil::actions($request);
  56. $params = $this->request->all();
  57. // 记录用户请求参数
  58. LogUtil::info('请求参数', $action['controller'], $action['action'], $params);
  59. //接口限流,写到中间件中
  60. if (!RedisUtil::getInstance(RedisKeyEnum::API_REQUEST_TRAFFIC)->requestLimit("{$action['controller']}/{$action['action']}", 1, 20000)) {
  61. LogUtil::info('当前访问人数过多,请稍后再试', $action['controller'], $action['action']);
  62. return $this->response206();
  63. }
  64. $token = $this->request->header('token');
  65. if (empty($token)) $token = $params['token'] ?? '';
  66. if (!empty($token) && !in_array("{$action['controller']}/{$action['action']}", self::tokenWhiteList())) {
  67. LogUtil::info('token 验证开始', self::LOG_MODULE, self::LOG_ACTION, (string)$token);
  68. // 校验token
  69. if (!$user_id = $this->checkToken($token)){
  70. return $this->response401();
  71. }
  72. // 查询并记录用户信息
  73. $user = (new UserModel())->authUserInfo($user_id);
  74. if (!$user) {
  75. LogUtil::warning('账号不存在', self::LOG_MODULE, self::LOG_ACTION, ['user_id', $user_id]);
  76. return $this->response401();
  77. }
  78. LogUtil::info('用户编号', $action['controller'], $action['action'], $user_id);
  79. AuthUser::getInstance()->set(json_decode(json_encode($user), true));
  80. }
  81. return $handler->handle($request);
  82. }
  83. /**
  84. * 校验token
  85. *
  86. * @param string $token
  87. * @return false|int
  88. */
  89. public function checkToken(string $token): false|int
  90. {
  91. $checkToken = Token::get($token);
  92. if (!$checkToken) {
  93. LogUtil::warning('token 验证失败', self::LOG_MODULE, self::LOG_ACTION, $checkToken);
  94. return false;
  95. }
  96. //验证参数信息
  97. if (empty($checkToken['user_id'])) {
  98. LogUtil::warning('token 参数不全', self::LOG_MODULE, self::LOG_ACTION, $checkToken);
  99. return false;
  100. }
  101. return (int)$checkToken['user_id'];
  102. }
  103. /**
  104. * 令牌失效
  105. *
  106. * @param string $message
  107. * @param $result
  108. * @return ResponseInterface
  109. */
  110. private function response401(string $message = '令牌失效,请稍后重试!', $result = null): ResponseInterface
  111. {
  112. // 记录令牌校验
  113. $action = $this->action;
  114. LogUtil::info($message, $action['controller'], $action['action'], $result);
  115. return AppResult::response401($message, $result);
  116. }
  117. /**
  118. * 请求频繁
  119. *
  120. * @param string $message
  121. * @param $result
  122. * @return ResponseInterface
  123. */
  124. private function response206(string $message = '当前访问人数过多,请稍后再试!', $result = null): ResponseInterface
  125. {
  126. // 记录令牌校验
  127. $action = $this->action;
  128. LogUtil::info($message, $action['controller'], $action['action'], $result);
  129. return AppResult::response206($message, $result);
  130. }
  131. /**
  132. * token校验黑名单
  133. * @return string[]
  134. */
  135. public function tokenWhiteList(): array
  136. {
  137. return [
  138. 'v1/Common/PassportController/login',
  139. 'v1/Common/PassportController/wxLogin',
  140. ];
  141. }
  142. }