MongoUserLoginJob.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. <?php
  2. namespace App\Jobs;
  3. use App\Model\Mongo\UserLoginLogModel;
  4. use App\Repositories\Utils\TelegramRepository;
  5. use Carbon\Carbon;
  6. use Hyperf\AsyncQueue\Job;
  7. use Psr\SimpleCache\CacheInterface;
  8. use Zhuzhichao\IpLocationZh\Ip;
  9. class MongoUserLoginJob extends Job
  10. {
  11. protected $params = [];
  12. public function __construct($params = [])
  13. {
  14. $this->params = $params;
  15. }
  16. public function handle()
  17. {
  18. $isEnableTelegram = true;
  19. $this->insertLog();
  20. if ($isEnableTelegram) {
  21. $cacheKey = $this->getCacheKey($this->params['device_no']);
  22. $cacheData = make(CacheInterface::class)->get($cacheKey);
  23. $diffHours = 99999999;
  24. if (!empty($cacheData['time'])) {
  25. $diffHours = abs(Carbon::parse($cacheData['time'])->diffInHours(Carbon::now()));
  26. }
  27. if ($diffHours > 24) {
  28. $this->reportSameDeviceNo();
  29. }
  30. }
  31. }
  32. private function insertLog()
  33. {
  34. $arrIpAddr = Ip::find($this->params['ip']);
  35. array_pop($arrIpAddr); //剔除最后一个下标, 国标
  36. $arrIpAddr = array_filter($arrIpAddr);
  37. $ipAddr = !empty($arrIpAddr) ? implode('|', $arrIpAddr) : '';
  38. $nowDate = toMongoIsoDate(Carbon::now());
  39. $setarr = [
  40. 'user_uid' => $this->params['user_id'],
  41. 'login_at' => $nowDate,
  42. 'version' => $this->params['version'],
  43. 'device_type' => $this->params['device_type'],
  44. 'device_no' => $this->params['device_no'],
  45. 'finger_hash' => $this->params['finger_hash'],
  46. 'ip' => $this->params['ip'],
  47. 'ip_addr' => $ipAddr,
  48. ];
  49. make(UserLoginLogModel::class)->db()->insertOne($setarr);
  50. }
  51. private function reportSameDeviceNo()
  52. {
  53. $arrDiff = [];
  54. // $tmpIp = '180.142.72.108';
  55. $tmpIp = $this->params['ip'];
  56. $pipeline = [
  57. [
  58. '$match' => [
  59. 'device_no' => $this->params['device_no'],
  60. 'ip' => [
  61. '$ne' => $tmpIp,
  62. ],
  63. ],
  64. ],
  65. [
  66. '$group' => [
  67. '_id' => '$ip',
  68. 'ip_addr' => [
  69. '$first' => '$ip_addr',
  70. ],
  71. 'mid' => [
  72. '$first' => '$_id',
  73. ],
  74. 'user_uid' => [
  75. '$first' => '$user_uid',
  76. ],
  77. 'list_login_at' => [
  78. '$push' => '$login_at',
  79. ],
  80. 'last_login_at' => [
  81. '$first' => '$login_at',
  82. ],
  83. 'device_type' => [
  84. '$first' => '$device_type',
  85. ],
  86. 'version' => [
  87. '$first' => '$version',
  88. ],
  89. ],
  90. ],
  91. [
  92. '$sort' => [
  93. 'last_login_at' => -1
  94. ],
  95. ],
  96. [
  97. '$limit' => 6,
  98. ],
  99. ];
  100. $options = [];
  101. /**
  102. * @var \MongoDB\Driver\Cursor $cursor
  103. */
  104. $cursor = make(UserLoginLogModel::class)->db()->aggregate($pipeline, $options);
  105. if (!$cursor->isDead()) {
  106. $tempArrIpAddr = Ip::find($this->params['ip']);
  107. array_pop($tempArrIpAddr); //剔除最后一个下标, 国标
  108. $tempArrIpAddr = array_filter($tempArrIpAddr); // 入库的这个IP和以前的对比
  109. $i = 0;
  110. foreach ($cursor as $itemObj) {
  111. $id = $itemObj->mid->__toString();
  112. $isDiff = false;
  113. $ipAddr = $itemObj->ip_addr;
  114. $arrIpAddr = !empty($ipAddr) ? explode('|', $ipAddr) : [];
  115. /**
  116. * @var \ArrayObject $listLoginAt
  117. */
  118. $listLoginAt = $itemObj->list_login_at;
  119. $listLoginAt->count();
  120. $lastLoginAt = $itemObj->last_login_at;
  121. $ip = $itemObj->_id;
  122. $userUid = $itemObj->user_uid;
  123. $version = $itemObj->version;
  124. $deviceType = $itemObj->device_type;
  125. $tmpData = [
  126. 'user_uid' => $userUid,
  127. 'device_no' => $this->params['device_no'],
  128. 'device_type' => $deviceType,
  129. 'version' => $version,
  130. 'login_at' => null,
  131. 'ip' => $ip,
  132. 'ip_addr' => $ipAddr,
  133. ];
  134. if (!empty($tempArrIpAddr) && !empty($arrIpAddr) && count($tempArrIpAddr) >= 2 && count($arrIpAddr) >= 2) {
  135. if ($tempArrIpAddr[0] != $arrIpAddr[0]) {
  136. $isDiff = true;
  137. $tmpData['login_at'] = $lastLoginAt;
  138. } elseif ($tempArrIpAddr[1] != $arrIpAddr[1]) {
  139. $isDiff = true;
  140. $tmpData['login_at'] = $lastLoginAt;
  141. }
  142. }
  143. if ($isDiff) {
  144. $arrDiff[] = $tmpData;
  145. }
  146. $i++;
  147. }
  148. }
  149. if (!empty($arrDiff)) {
  150. $nowDate = Carbon::now()->toDateTimeString();
  151. $arrIpAddr = Ip::find($this->params['ip']);
  152. array_pop($arrIpAddr); //剔除最后一个下标, 国标
  153. $arrIpAddr = array_filter($arrIpAddr);
  154. $nowIpAddr = !empty($arrIpAddr) ? implode('|', $arrIpAddr) : '';
  155. $arrCurrentLogin = [
  156. 'user_uid' => $this->params['user_id'],
  157. 'device_no' => $this->params['device_no'],
  158. 'device_type' => $this->params['device_type'],
  159. 'version' => $this->params['version'],
  160. 'login_at' => toMongoIsoDate($nowDate),
  161. 'ip' => $this->params['ip'],
  162. 'ip_addr' => $nowIpAddr,
  163. ];
  164. $cacheKey = $this->getCacheKey($this->params['device_no']);
  165. make(CacheInterface::class)->set($cacheKey, ['time' => $nowDate], 24 * 60 * 60);
  166. $appFlag = env('APP_NAME', '');
  167. $msgContent = <<<EOT
  168. 【事件】疑似同设备号不同人登陆(根据ip地区)
  169. 【项目标识】{$appFlag}
  170. 【报告时间】{$nowDate}
  171. 【清单如下】
  172. ------------------
  173. EOT;
  174. $msgContent .= $this->formatCurrentLoginMsg($arrCurrentLogin). "\n";
  175. foreach ($arrDiff as $k => $v) {
  176. $liNo = $k + 1;
  177. $msgContent .= $this->formatAddonMsg($liNo, $v);
  178. }
  179. $msgContent = "\r\n" .rtrim($msgContent) . "\n";
  180. $msgContent .= "\n---------------\n";
  181. make(TelegramRepository::class)->sendCommonText($msgContent);
  182. }
  183. }
  184. private function formatAddonMsg($liNo, $v)
  185. {
  186. $loginDate = !empty($v['login_at']) ? mongoIsoDateToCarbonTime($v['login_at']) : '未知';
  187. $ipInfo = $v['ip_addr'] . '('. $v['ip'] .')';
  188. $deviceTypeName = '未知';
  189. if ($v['device_type'] == 'I') {
  190. $deviceTypeName = 'iOS';
  191. } elseif ($v['device_type'] == 'A') {
  192. $deviceTypeName = 'Android';
  193. } elseif ($v['device_type'] == 'H') {
  194. $deviceTypeName = 'WebH5';
  195. }
  196. $userUid = $v['user_uid'];
  197. $deviceNo = $v['device_no'];
  198. $version = $v['version'];
  199. $strTpl = <<<EOT2
  200. 序号: %s
  201. 用户UID: %s
  202. 设备号: %s
  203. 设备类型: %s
  204. 版本: %s
  205. 登陆时间 :%s
  206. 登陆IP: %s
  207. EOT2;
  208. $msg = sprintf($strTpl, $liNo, $userUid, $deviceNo, $deviceTypeName, $version, $loginDate, $ipInfo);
  209. return $msg;
  210. }
  211. private function formatCurrentLoginMsg($v)
  212. {
  213. $loginDate = !empty($v['login_at']) ? mongoIsoDateToCarbonTime($v['login_at']) : '未知';
  214. $ipInfo = $v['ip_addr'] . '('. $v['ip'] .')';
  215. $deviceTypeName = '未知';
  216. if ($v['device_type'] == 'I') {
  217. $deviceTypeName = 'iOS';
  218. } elseif ($v['device_type'] == 'A') {
  219. $deviceTypeName = 'Android';
  220. } elseif ($v['device_type'] == 'H') {
  221. $deviceTypeName = 'WebH5';
  222. }
  223. $userUid = $v['user_uid'];
  224. $deviceNo = $v['device_no'];
  225. $version = $v['version'];
  226. $strTpl = <<<EOT2
  227. 本次登陆用户UID: %s
  228. 本次登陆设备号: %s
  229. 本次登陆设备类型: %s
  230. 本次登陆APP版本: %s
  231. 本次登陆登陆时间 :%s
  232. 本次登陆登陆IP: %s
  233. EOT2;
  234. $msg = sprintf($strTpl, $userUid, $deviceNo, $deviceTypeName, $version, $loginDate, $ipInfo);
  235. return $msg;
  236. }
  237. private function getCacheKey($deviceNo)
  238. {
  239. $key = 'user:device_same_notify:'. $deviceNo;
  240. return $key;
  241. }
  242. }