BehaviorLogMiddleware.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <?php
  2. declare (strict_types = 1);
  3. namespace app\middleware;
  4. use app\model\UserBehaviorLogModel;
  5. use think\facade\Request;
  6. use Closure;
  7. /**
  8. * 操作日志中间件
  9. */
  10. class BehaviorLogMiddleware
  11. {
  12. // 不记录日志的控制器/方法
  13. private $excludeActions = [
  14. // 查询类操作(不改变数据的操作)
  15. 'User/list',
  16. 'User/detail',
  17. 'UserRole/list',
  18. 'UserRole/detail',
  19. 'Game/list',
  20. 'Game/detail',
  21. 'Game/statistics',
  22. 'Game/getPlatforms',
  23. 'Player/list',
  24. 'Player/detail',
  25. 'Player/statistics',
  26. 'Menu/list',
  27. 'Menu/getUserMenus',
  28. 'LoginLog/list',
  29. 'LoginLog/detail',
  30. 'LoginLog/statistics',
  31. 'LoginLog/recentLogs',
  32. 'BehaviorLog/list',
  33. 'BehaviorLog/detail',
  34. 'BehaviorLog/statistics',
  35. 'BehaviorLog/recentLogs',
  36. 'BehaviorLog/getBehaviorTypes',
  37. // 登录相关
  38. 'User/login',
  39. 'User/logout',
  40. ];
  41. // 需要过滤的敏感参数
  42. private $filterParams = [
  43. 'password',
  44. 'token',
  45. 'auth_token',
  46. 'secret_key',
  47. 'private_key',
  48. ];
  49. /**
  50. * 处理请求
  51. */
  52. public function handle($request, Closure $next)
  53. {
  54. // 执行请求
  55. $response = $next($request);
  56. // 请求执行完后记录日志
  57. $this->recordBehaviorLog($request, $response);
  58. return $response;
  59. }
  60. /**
  61. * 记录操作日志
  62. */
  63. private function recordBehaviorLog($request, $response)
  64. {
  65. try {
  66. // 检查是否需要记录日志
  67. if (!$this->shouldRecord($request)) {
  68. return;
  69. }
  70. // 获取用户信息
  71. $userInfo = $request->userInfo ?? [];
  72. if (empty($userInfo)) {
  73. return; // 没有用户信息则不记录
  74. }
  75. // 获取控制器和方法名
  76. $controller = Request::controller();
  77. $action = Request::action();
  78. $behavior = $controller . '/' . $action;
  79. // 获取权限配置中的行为描述
  80. $permissions = config('permission.permissions');
  81. $behaviorText = '';
  82. if (isset($permissions[$controller]['actions'][$action])) {
  83. $behaviorText = $permissions[$controller]['module'] . '-' . $permissions[$controller]['actions'][$action];
  84. } else {
  85. $behaviorText = $behavior;
  86. }
  87. // 获取请求参数并过滤敏感信息
  88. $params = Request::param();
  89. foreach ($this->filterParams as $key) {
  90. if (isset($params[$key])) {
  91. unset($params[$key]);
  92. }
  93. }
  94. // 判断操作状态(根据响应状态判断)
  95. $status = $this->getOperationStatus($response);
  96. // 构建日志数据
  97. $data = [
  98. 'merchant_id' => $userInfo['merchant_id'] ?? 0,
  99. 'user_id' => $userInfo['user_id'] ?? 0,
  100. 'behavior' => $behaviorText,
  101. 'behavior_desc' => json_encode($params, JSON_UNESCAPED_UNICODE),
  102. 'behavior_ip' => getClientIp(),
  103. 'behavior_url' => Request::pathinfo(),
  104. 'behavior_status' => $status
  105. ];
  106. // 异步记录日志(避免影响响应性能)
  107. $this->asyncRecordLog($data);
  108. } catch (\Exception $e) {
  109. // 记录日志失败不影响业务
  110. // 可以在这里记录到错误日志中
  111. }
  112. }
  113. /**
  114. * 判断是否需要记录日志
  115. */
  116. private function shouldRecord($request): bool
  117. {
  118. // 只记录POST、PUT、DELETE请求
  119. $method = Request::method();
  120. if (!in_array($method, ['POST', 'PUT', 'DELETE', 'PATCH'])) {
  121. return false;
  122. }
  123. // 检查是否在排除列表中
  124. $controller = Request::controller();
  125. $action = Request::action();
  126. $currentAction = $controller . '/' . $action;
  127. if (in_array($currentAction, $this->excludeActions)) {
  128. return false;
  129. }
  130. // 检查权限配置中是否存在该操作
  131. $permissions = config('permission.permissions');
  132. if (!isset($permissions[$controller]['actions'][$action])) {
  133. return false; // 权限配置中不存在的操作不记录
  134. }
  135. return true;
  136. }
  137. /**
  138. * 根据响应判断操作状态
  139. */
  140. private function getOperationStatus($response): int
  141. {
  142. try {
  143. // 获取响应内容
  144. $content = $response->getContent();
  145. $data = json_decode($content, true);
  146. // 根据响应的code字段判断
  147. if (isset($data['code'])) {
  148. return $data['code'] == 200 ? UserBehaviorLogModel::STATUS_SUCCESS : UserBehaviorLogModel::STATUS_FAILED;
  149. }
  150. // 根据HTTP状态码判断
  151. $statusCode = $response->getCode();
  152. return $statusCode >= 200 && $statusCode < 300 ? UserBehaviorLogModel::STATUS_SUCCESS : UserBehaviorLogModel::STATUS_FAILED;
  153. } catch (\Exception $e) {
  154. // 默认为失败
  155. return UserBehaviorLogModel::STATUS_FAILED;
  156. }
  157. }
  158. /**
  159. * 异步记录日志
  160. */
  161. private function asyncRecordLog(array $data)
  162. {
  163. // 这里可以使用队列异步处理
  164. // 暂时直接记录
  165. UserBehaviorLogModel::recordBehavior($data);
  166. }
  167. }