ruleCheckService = new RuleCheckService(); } /** * 处理风控事件 * @param array $eventData 事件数据 * @return array 处理结果 */ public function processEvent(array $eventData) { try { // 1. 数据验证 $this->validateEventData($eventData); // 2. 检查黑白名单 if ($this->checkBlackList($eventData)) { return ['is_blocked' => true, 'msg' => '账号已被封禁']; } // 3. 执行策略检查 $strategyResults = $this->executeStrategies($eventData); // 4. 处理异常数据 if (!empty($strategyResults['exceptions'])) { $this->handleExceptions($strategyResults['exceptions'], $eventData); } // 5. 清理过期数据 $this->cleanExpiredData(); // 6. 检查异常程度 $riskLevel = $this->checkRiskLevel($eventData); return [ 'is_blocked' => $riskLevel['is_blocked'], 'is_risky' => $riskLevel['is_risky'], 'risk_level' => $riskLevel['level'], 'msg' => $riskLevel['msg'] ]; } catch (Exception $e) { // 记录错误日志 \think\Log::error('风控处理异常:' . $e->getMessage()); return ['is_blocked' => false, 'is_risky' => false, 'msg' => '系统异常']; } } /** * 验证事件数据 * @param array $eventData * @throws Exception */ private function validateEventData(array $eventData) { $requiredFields = ['event_type', 'member_id', 'ip', 'imei', 'timestamp']; foreach ($requiredFields as $field) { if (!isset($eventData[$field]) || empty($eventData[$field])) { throw new Exception("缺少必要字段:{$field}"); } } } /** * 检查黑名单 * @param array $eventData * @return bool */ private function checkBlackList(array $eventData) { $cacheKey = self::CACHE_PREFIX . 'blacklist:'; // 检查IP if ($this->checkInList($eventData['ip'], 'ip', 'black', $cacheKey)) { return true; } // 检查IMEI if ($this->checkInList($eventData['imei'], 'imei', 'black', $cacheKey)) { return true; } // 检查用户ID if ($this->checkInList($eventData['member_id'], 'member_id', 'black', $cacheKey)) { return true; } return false; } /** * 检查是否在名单中 * @param string $value * @param string $type * @param string $listType * @param string $cacheKey * @return bool */ private function checkInList($value, $type, $listType, $cacheKey) { $key = $cacheKey . $listType . ':' . $type . ':' . $value; // 先查缓存 if (Cache::get($key)) { return true; } // 查数据库 $exists = Db::name('fk_roster_lists') ->where([ 'object_type' => $type, 'object_value' => $value, 'list_type' => $listType, 'status' => 1 ]) ->where(function ($query) { $query->where('expire_time', '>', time()) ->whereOr('expire_time', 0); }) ->find(); if ($exists) { Cache::set($key, 1, self::CACHE_TIME); return true; } return false; } /** * 执行策略检查 * @param array $eventData * @return array */ private function executeStrategies(array $eventData) { $exceptions = []; // 获取相关策略 $strategies = Db::name('fk_strategies') ->where('status', 1) ->where('event_type', $eventData['event_type']) ->order('weight', 'desc') ->select(); foreach ($strategies as $strategy) { // 获取策略详情 $details = Db::name('fk_strategy_details') ->alias('d') ->join('fk_rules r', 'd.rule_id = r.id') ->where('d.strategy_id', $strategy['id']) ->where('r.status', 1) ->select(); dump($details->toArray()); foreach ($details as $detail) { if ($this->checkRule($detail, $eventData)) { $exceptions[] = [ 'strategy_id' => $strategy['id'], 'rule_id' => $detail['rule_id'], 'object_type' => $detail['object_type'], 'object_value' => $eventData[$detail['object_type']], 'exception_level' => $detail['exception_level'], 'expire_time' => time() + $detail['expire_time'] ]; } } } return ['exceptions' => $exceptions]; } /** * 检查规则 * @param array $detail * @param array $eventData * @return bool */ private function checkRule(array $detail, array $eventData) { // 根据规则类型执行不同的检查逻辑 switch ($detail['rule_type']) { case 'frequency': return $this->ruleCheckService->checkFrequencyRule($detail, $eventData); case 'statistics': return $this->ruleCheckService->checkStatisticsRule($detail, $eventData); default: return false; } } /** * 处理异常数据 * @param array $exceptions * @param array $eventData */ private function handleExceptions(array $exceptions, array $eventData) { Db::startTrans(); try { foreach ($exceptions as $exception) { // 记录异常记录 Db::name('fk_exception_records')->insert([ 'strategy_id' => $exception['strategy_id'], 'rule_id' => $exception['rule_id'], 'object_type' => $exception['object_type'], 'object_value' => $exception['object_value'], 'exception_level' => $exception['exception_level'], 'expire_time' => $exception['expire_time'], 'create_time' => time() ]); // 更新异常对象 $this->updateExceptionObject($exception); } Db::commit(); } catch (Exception $e) { Db::rollback(); throw $e; } } /** * 更新异常对象 * @param array $exception */ private function updateExceptionObject(array $exception) { $object = Db::name('fk_exception_objects') ->where([ 'object_type' => $exception['object_type'], 'object_value' => $exception['object_value'] ]) ->find(); if ($object) { // 更新异常程度 $newLevel = min(100, $object['exception_level'] + $exception['exception_level']); Db::name('fk_exception_objects') ->where('id', $object['id']) ->update([ 'exception_level' => $newLevel, 'update_time' => time() ]); } else { // 创建新异常对象 Db::name('fk_exception_objects')->insert([ 'object_type' => $exception['object_type'], 'object_value' => $exception['object_value'], 'exception_level' => $exception['exception_level'], 'create_time' => time(), 'update_time' => time() ]); } } /** * 清理过期数据 */ private function cleanExpiredData() { $now = time(); // 清理过期异常记录 Db::name('fk_exception_records') ->where('expire_time', '<', $now) ->where('expire_time', '>', 0) ->delete(); // 更新异常对象异常程度 $expiredRecords = Db::name('fk_exception_records') ->where('expire_time', '<', $now) ->where('expire_time', '>', 0) ->select(); foreach ($expiredRecords as $record) { $object = Db::name('fk_exception_objects') ->where([ 'object_type' => $record['object_type'], 'object_value' => $record['object_value'] ]) ->find(); if ($object) { $newLevel = max(0, $object['exception_level'] - $record['exception_level']); Db::name('fk_exception_objects') ->where('id', $object['id']) ->update([ 'exception_level' => $newLevel, 'update_time' => $now ]); } } } /** * 检查风险等级 * @param array $eventData * @return array */ private function checkRiskLevel(array $eventData) { $riskLevel = 0; $isBlocked = false; $isRisky = false; $msg = ''; // 检查各个维度的异常程度 $dimensions = ['ip', 'imei', 'member_id']; if (isset($eventData['id_card'])) { $dimensions[] = 'id_card'; } foreach ($dimensions as $dimension) { $object = Db::name('fk_exception_objects') ->where([ 'object_type' => $dimension, 'object_value' => $eventData[$dimension] ]) ->find(); if ($object) { $riskLevel = max($riskLevel, $object['exception_level']); // 如果异常程度超过80,加入黑名单 if ($object['exception_level'] >= 80) { $this->addToBlackList($dimension, $eventData[$dimension]); $isBlocked = true; $msg = '账号已被封禁'; } // 如果异常程度超过50,标记为风险 elseif ($object['exception_level'] >= 50) { $isRisky = true; $msg = '需要验证'; } } } return [ 'is_blocked' => $isBlocked, 'is_risky' => $isRisky, 'level' => $riskLevel, 'msg' => $msg ]; } /** * 添加到黑名单 * @param string $type * @param string $value */ private function addToBlackList($type, $value) { // 检查是否已在黑名单 $exists = Db::name('fk_roster_lists') ->where([ 'object_type' => $type, 'object_value' => $value, 'list_type' => 'black' ]) ->find(); if (!$exists) { Db::name('fk_roster_lists')->insert([ 'object_type' => $type, 'object_value' => $value, 'list_type' => 'black', 'create_time' => time(), 'status' => 1 ]); // 清除缓存 Cache::rm(self::CACHE_PREFIX . 'blacklist:black:' . $type . ':' . $value); } } }