BehaviorLogMiddleware.php 5.7 KB

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