getClientRealIp(); // 参数校验 validate(LoginValidate::class)->scene('sendEmail')->check($param); $param['email'] = trim($param['email']); // 邮箱类型校验 去除国内邮箱 if ($this->checkForbidEmail($param['email'])) { return $this->toData('500', lang('email_not_supported')); } // 每天获取code 次数限制 $sendCodeKey = 'USER:SEND_CODE_NUM:' . $ip; if ($this->checkGetNoTradeCodeNum($sendCodeKey)) { return $this->toData('500', lang('exceeding_the_maximum_number')); } // 获取发送的邮件内容 $content = $this->getEmailContent(); $content['email'] = $param['email']; // 将发送邮件任务添加到异步队列 $queuename = 'app\home\job\SendEmail'; Queue::push($queuename, $content, 'sendEmail'); // 邮件code存到缓存(未登录操作共用) $key = 'DB:USER:UNLOGIN:EMAIL_CODE:' . $param['email']; $this->insertCodeToCache($key, $content['code'], 300); // 记录已经发送的code次数 $this->updateHadGetCodeNumCache($sendCodeKey); // 返回结果 return $this->toData('0', lang('email_send_successfully')); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('500', $message); } catch (\Exception $exception) { // 异常情况 return $this->toData('500', lang('system_busy'), [$exception->getMessage()]); } } /** * @desc 邮箱注册用户 * @param $param * @return array * @throws InvalidArgumentException * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function registerEmail($param): array { try { // 获取客户端ip $ip = $this->getClientRealIp(); $agentCode = $param['agent_code'] ?? ''; // 代理邀请码(该邀请码只限于管理端账号中) $inviteCode = $param['invite_code'] ?? ''; // 邀请码 (该邀请码即可以是管理端账号的邀请码,也可以是用户表中的邀请码) $chCode = $param['ch_code'] ?? ''; // 注册渠道标识码 $phone = $param['phone']; $email = $param['email']; // 邮件注册参数校验 validate(LoginValidate::class)->scene('emailRegister')->check($param); // 判断注册数量 ip每天可注册数量 $ipCanRegisterNumPerIpPerDay = 'USER:REGISTER:' . $ip; if ($this->checkRegisterLimit($ipCanRegisterNumPerIpPerDay)) { return $this->toData('500', lang('exceeding_the_maximum_number')); } // 验证验证码 $emailKey = 'DB:USER:UNLOGIN:EMAIL_CODE:' . $param['email']; if (!$this->checkCode($emailKey, $param['email_code'])) { //注册验证码 $reg_key = "USER:REG:CODE"; if (!$this->checkCode($reg_key, $param['email_code'])) { return $this->toData('500', lang('incorrect_verification_code')); } else { $code = random_int(1000, 9999); $this->insertCodeToCache($reg_key, $code, 300); } } // 邮箱是否已经存在 $emailExists = UserModel::checkEmailExists($email); if ($emailExists) { return $this->toData('500', lang('email_has_already_been_registered')); } // 获取代理ID (后续要查询代理下的客服,将用户与其中一个客服绑定) $agentId = 0; if (!empty($agentCode)) { $agentId = AdminModel::getIdByInviteCode($agentCode); } // 获取邀请码对应的账号ID(可以是管理端的账号,也可以是用户列表中的账号) $parentAdminId = 0; $parentUserId = 0; if (!empty($inviteCode)) { $parentAdminId = AdminModel::getIdByInviteCode($inviteCode); // 先从管理端账号中查找是否存在邀请码对应的账号 if ($parentAdminId) { $agentId = $parentAdminId; } else { $parentUserId = $this->getParentIdByInviteCode($inviteCode); // 再从用户账号中查找是否存在邀请码对应的账号 } } // 如果没有传递代理邀请码,也没有根据invite_code找到管理端账号,则设置一个默认的代理 if (empty($agentId) && empty($parentAdminId)) { $agentId = AdminModel::getDefaultAgentId(); if (empty($agentId)) { return $this->toData('500', lang('missing_agent_id')); } } // 入库 $userNo = $this->getUniqUserNo(); $salt = env('ENCRYPT.SALT'); $password = (new UnqId())->encryptPassword($param['password'], $salt); $userInviteCode = $this->getUniqInviteCode(); // 需要开启事务 \think\facade\Db::transaction(function () use ($chCode, $phone, $email, $userNo, $userInviteCode, $parentUserId, $password, $ip, $salt, $agentId) { // 截取邮箱@前的部分作为用户名称 $pos = strpos($email, '@'); if ($pos !== false) { $userNickName = substr($email, 0, $pos); } // 查询父级用户 $parentIds = ''; $originUserId = 0; if($parentUserId > 0){ $parentUser = UserModel::where('user_id', $parentUserId)->findOrEmpty(); if($parentUser){ $parentIds = $parentUser['parent_ids']? $parentUser['parent_ids'].','.$parentUserId : $parentUserId; // 如果祖先id = 0 说明这个父级就是祖先id $originUserId = $parentUser['origin_user_id'] == 0 ? $parentUserId : $parentUser['origin_user_id']; } } $regUser = UserModel::create([ 'user_no' => $userNo, 'nick_name' => $userNickName ?? 'user_' . time(), 'email' => $email, 'phone_number' => $phone, 'invite_code' => $userInviteCode, 'parent_id' => $parentUserId, 'agent_id' => $agentId, 'login_password' => $password, 'salt' => $salt, 'reg_ip' => $ip, 'is_test_user' => UserModel::IS_TEST_USER_NO, 'origin_user_id' => $originUserId, 'ch_code' => $chCode, 'parent_ids' => $parentIds, 'create_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s'), ]); $userId = $regUser->user_id; // 生成钱包地址 (new UserService())->doRegInitUserInfo($userId, $parentUserId); // 请求聊天服务,注册聊天账号 $chatData = [ 'Username' => $userNo, 'Password' => '123456', 'Nickname' => $regUser->nick_name, 'Avatar' => env('USER.DEFAULT_HEAD_IMG_PATH'), 'Email' => $regUser->email, ]; $chatUrl = env('CHAT_SERVER.BASE_URL') . '/api/user/register'; $chatRes = (new \app\utility\RequestChatServer())->ReqChatServer($chatUrl, $chatData); if (!isset($chatRes['data']['uuid'])) { return $this->toData('500', lang('account_registration_failed')); } // 绑定注册账号与聊天账号 UserChatLinkModel::create([ 'user_id' => $userId, 'user_type' => 1, 'chat_uuid' => $chatRes['data']['uuid'], 'chat_name' => $chatRes['data']['username'] ]); // 如果有代理,绑定到代理下一个客服(轮询客服绑定) if ($agentId > 0 ) { $customerIds = AdminModel::getCustomerIdsByAgentId($agentId); // 获取代理下的所有客服ID Log::info("邮箱注册 - 客服列表:".json_encode($customerIds)); if (empty($customerIds)) { return $this->toData('500', lang('account_registration_failed')); } $counterKey = 'counter_of_bind_customer:'.$agentId; $counterIndex = Cache::store('redis')->get($counterKey); //客服绑定计数器索引 if (empty($counterIndex)) { Cache::store('redis')->set($counterKey, 1); $tagCustomerId = $customerIds[0]; } else { Cache::store('redis')->inc($counterKey); //更新计数器索引 $tagIndex = $counterIndex % count($customerIds); $tagCustomerId = $customerIds[$tagIndex]; } Log::info("邮箱注册 - 当前绑定客服ID:".$tagCustomerId); if ($tagCustomerId > 0) { $regUser->customer_id = $tagCustomerId; $regUser->save(); } // 将注册账号的chat_id与绑定客服的chat_id加为好友 $customerChatInfo = UserChatLinkModel::where(['user_id'=>$tagCustomerId, 'user_type'=>UserChatLinkModel::USER_CHAT_LINK_USER_TYPE_ADMIN])->find(); //查询客服的聊天账号uuid if (empty($customerChatInfo)) { return $this->toData('500', lang('account_registration_failed')); } $chatFriendsData = [ 'UserUuid' => $chatRes['data']['uuid'], 'CustomerUuid' => $customerChatInfo->chat_uuid, ]; $chatFriendsUrl = env('CHAT_SERVER.BASE_URL') . '/api/eachOtherFriends'; $chatFriendsRes = (new \app\utility\RequestChatServer())->ReqChatServer($chatFriendsUrl, $chatFriendsData); Log::info("邮箱注册 - 用户与客服加好友结果:".json_encode($chatFriendsRes)); // 将当前用户加入到代理创建的群聊中 【需要查出当前用户的代理创建的群聊信息】 $agentGroup = UserChatGroupModel::where(['user_id'=>$agentId,'remark'=>UserChatGroupModel::USER_CHAT_GROUP_REMARK_ADMIN_INIT])->find(); if (empty($agentGroup)) { return $this->toData('500', lang('account_registration_failed')); } $joinChatGroupUrl = env('CHAT_SERVER.BASE_URL') . '/api/group/join/'.$chatRes['data']['uuid'].'/'.$agentGroup->group_uuid; $joinChatGroupRes = (new \app\utility\RequestChatServer())->ReqChatServer($joinChatGroupUrl, []); Log::info("邮箱注册 - 用户与客服加好友结果:".json_encode($joinChatGroupRes)); } }); // 删除缓存 $this->delCache($emailKey); // 累加已经注册的个数 $this->updateHadRegisterNumCache($ipCanRegisterNumPerIpPerDay); return $this->toData('0', lang('account_registration_successful')); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('500', $message); } catch (\Exception $exception) { trace('【注册错误】提交数据:'.json_encode($param), 'error'); trace('【注册错误】'.$exception->getMessage(), 'error'); return $this->toData('500', lang('system_busy'), [$exception->getMessage(), $exception->getTrace()]); } } /** * @desc 登陆业务处理接口 * @param array $param * @return array */ public function loginEmail(array $param): array { try { // 参数校验 邮箱 密码 validate(LoginValidate::class)->scene('emailLogin')->check($param); $param['email'] = trim($param['email']); // 查找邮箱 $userId = UserModel::getUserIdByEmail($param['email']); if ($userId <= 0) { return $this->toData('500', lang('user_does_not_exist')); } // 查找用户信息 $user = UserModel::getFieldsByUserId('invite_code,user_id,user_no,nick_name,is_real,login_password,salt', $userId); if (empty($user)) { return $this->toData('500', lang('user_does_not_exist')); } // 校验密码 $checkPasswordBool = (new UnqId())->checkPassword($param['password'], $user['login_password'], $user['salt']); if (!$checkPasswordBool) { return $this->toData('500', lang('incorrect_account_or_password')); } // 生成token $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); if (empty($token)) { return $this->toData('500', lang('system_busy')); } // 用户登陆之后需要进行的操作 异步完成 Queue::push('app\home\job\LoginDone', ['userId' => $userId, 'fields' => [ 'last_login_time' => date('Y-m-d H:i:s'), 'ip' => $this->getClientRealIp(), 'device' => $param['device'], ] ], 'loginDone'); // 将token存致缓存 覆盖新的缓存 实现单设备登陆 $this->setUserTokenCache($token, $userId); // 用户登记关系 (new UserService())->getUserLevel($userId); // 返回结果以及用户信息 return $this->toData('0', 'Request successful.', [ 'userId' => $userId, 'userNo' => $user['user_no'], 'nickName' => $user['nick_name'], 'inviteCode' => $user['invite_code'], 'isReal' => $user['is_real'], 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), 'token' => $token, ]); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('500', $message); } catch (InvalidArgumentException $invalidArgumentException) { return $this->toData('500', lang('system_busy')); } catch (\Exception $exception) { return $this->toData('500', lang('system_busy'), [$exception->getTrace()]); } } /** * @desc未登陆获取短信验证码 * @param array $param * @return array * @throws InvalidArgumentException */ public function sendSms(array $param): array { try { // 防止重复操作 单个ip 3秒钟内只能请求一次 $ip = $this->getClientRealIp(); // 参数校验 validate(LoginValidate::class)->scene('sendSms')->check($param); $param['nation'] = trim($param['nation']); $param['phone'] = trim($param['phone']); // 去除国内手机号 if ($this->checkForbidNation($param['nation'])) { return $this->toData('500', lang('unsupported_country_or_region')); } // 判断国家码是否有效 $nationExists = CountryModel::checkCodeExists($param['nation']); if (!$nationExists) { return $this->toData('500', lang('unsupported_country_or_region')); } // 发送次数校验 - 号码 $phoneSendCodeKey = 'USER:PHONE_SEND_CODE_NUM:' . $param['nation'].':'.$param['phone']; if ($this->checkGetNoTradeCodeNumPhone($phoneSendCodeKey)) { return $this->toData('100300', 'No worries. Please feel free to reach out again tomorrow.', []); } // 发送次数校验 - ip $ipSendCodeKey = 'USER:IP_SEND_CODE_NUM:' . $ip; if ($this->checkGetNoTradeCodeNum($ipSendCodeKey)) { return $this->toData('100300', 'No worries. Please feel free to reach out again tomorrow.', []); } // 获取发送内容 $content = $this->getSmsContent(); $mobile = $param['nation'] . $param['phone']; $content['mobile'] = $mobile; // 异步发送 $queuename = 'app\home\job\SendSms'; Queue::push($queuename, $content, 'sendSms'); // 短信code存到缓存(未登录操作共用) $key = 'DB:USER:UNLOGIN:SMS_CODE:' . $mobile; $this->insertCodeToCache($key, $content['code'], 300); // 累加已经获取的次数 $this->updateHadGetCodeNumCache($phoneSendCodeKey); $this->updateHadGetCodeNumCache($ipSendCodeKey); // 返回结果 return $this->toData('0', lang('message_has_been_sent')); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('100400', $message); } catch (\Exception $exception) { trace('【注册错误】提交数据:'.json_encode($param), 'error'); trace('【注册错误】'.$exception->getMessage(), 'error'); return $this->toData('500', lang('system_busy'), [$exception->getMessage()]); } } /** * @desc 短信注册 * @param array $param * @return array * @throws InvalidArgumentException */ public function registerSms(array $param): array { try { // 防止重复操作 $ip = $this->getClientRealIp(); $agentCode = $param['agent_code'] ?? ''; // 代理邀请码(该邀请码只限于管理端账号中) $inviteCode = $param['invite_code'] ?? ''; // 邀请码 (该邀请码即可以是管理端账号的邀请码,也可以是用户表中的邀请码) $chCode = $param['ch_code'] ?? ''; // p2项目调整,手机号注册时候也需要上传邮箱地址 if (empty($param['email'])) { return $this->toData('400', lang('parameter_error')); } // 是否上传了实名认证信息,上传了实名认证信息时is_verify=1,否则is_verify=0 $isVerify = $param['is_verify'] ?? 0; if ($isVerify == 1) { if (empty($param['verify_name']) || empty($param['verify_surname']) || empty($param['verify_code']) || empty($param['verify_front_img']) || empty($param['verify_country']) || empty($param['verify_birth_day']) || empty($param['verify_gender']) || empty($param['verify_email'])) { return $this->toData('400', lang('parameter_error')); } } // 短信注册参数校验 validate(LoginValidate::class)->scene('smsRegister')->check($param); // 判断注册数量 ip每天可注册数量 $ipCanRegisterNumPerIpPerDay = 'USER:REGISTER:' . $ip; $this->checkRegisterLimit($ipCanRegisterNumPerIpPerDay); // 校验验证码 $mobile = $param['nation'] . $param['phone']; $smsKey = 'DB:USER:UNLOGIN:SMS_CODE:' . $mobile; if ($param['sms_code'] != 8888) { // 方便测试,8888为万能验证码 if (!$this->checkCode($smsKey, $param['sms_code'])) { return $this->toData('500', lang('incorrect_verification_code')); //注册验证码 // $reg_key = "USER:REG:CODE"; // if (!$this->checkCode($reg_key, $param['sms_code'])) { // return $this->toData('100300', 'The verification code is incorrect.', []); // } } } // 手机号是否已经存在 $phoneExists = UserModel::checkPhoneExists($param['phone']); if ($phoneExists) { return $this->toData('500', lang('phone_number_has_already_been_registered')); } // 获取代理ID (后续要查询代理下的客服,将用户与其中一个客服绑定) $agentId = 0; if (!empty($agentCode)) { $agentId = AdminModel::getIdByInviteCode($agentCode); } // 获取邀请码对应的账号ID(可以是管理端的账号,也可以是用户列表中的账号) $parentAdminId = 0; $parentUserId = 0; if (!empty($inviteCode)) { $parentAdminId = AdminModel::getIdByInviteCode($inviteCode); // 先从管理端账号中查找是否存在邀请码对应的账号 if ($parentAdminId) { $agentId = $parentAdminId; } else { $parentUserId = $this->getParentIdByInviteCode($inviteCode); // 再从用户账号中查找是否存在邀请码对应的账号 } } // 如果没有传递代理邀请码,也没有根据invite_code找到管理端账号,则设置一个默认的代理 if (empty($agentId) && empty($parentAdminId)) { $agentId = AdminModel::getDefaultAgentId(); if (empty($agentId)) { return $this->toData('500', lang('missing_agent_id')); } } // 入库 $userNo = $this->getUniqUserNo(); $salt = env('ENCRYPT.SALT'); $password = (new UnqId())->encryptPassword($param['password'], $salt); $userInviteCode = $this->getUniqInviteCode(); // 需要开启事务 \think\facade\Db::transaction(function () use ($chCode, $param, $userNo, $userInviteCode, $parentUserId, $password, $ip, $salt, $agentId, $isVerify) { // 生成用户数据 $parentIds = ''; $originUserId = 0; if($parentUserId > 0){ $parentUser = UserModel::where('user_id', $parentUserId)->findOrEmpty(); if($parentUser){ $parentIds = $parentUser['parent_ids']? $parentUser['parent_ids'].','.$parentUserId : $parentUserId; // 如果祖先id = 0 说明这个父级就是祖先id $originUserId = $parentUser['origin_user_id'] == 0 ? $parentUserId : $parentUser['origin_user_id']; } } $regUser = UserModel::create([ 'country_code' => $param['nation'], 'email' => $param['email'], 'phone_number' => $param['phone'], 'user_no' => $userNo, 'invite_code' => $userInviteCode, 'parent_id' => $parentUserId, 'agent_id' => $agentId, 'real_status' => $isVerify ? 2 : 1, 'login_password' => $password, 'salt' => $salt, 'reg_ip' => $ip, 'is_test_user' => UserModel::IS_TEST_USER_NO, 'nick_name' => 'user_'.substr($param['phone'], -4), 'origin_user_id' => $originUserId, 'parent_ids' => $parentIds, 'ch_code' => $chCode, 'create_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s'), 'lever_status' => 3, // 直接通过 ]); $userId = $regUser->user_id; // 如果上传了实名认证信息,则添加实名认证数据 if ($isVerify == 1) { UserVerifyLogModel::create([ 'user_id' => $userId, 'surname' => $param['verify_surname'] ?? '', 'name' => $param['verify_name'] ?? '', 'code' => $param['verify_code'] ?? '', 'front_img' => $param['verify_front_img'], 'status' => 1, 'country' => $param['verify_country'] ?? 0, 'birth_day' => $param['verify_birth_day'], 'gender' => $param['verify_gender'], // 'addr' => $param['verify_addr'], // 'zip_code' => $param['verify_zip_code'], 'email' => $param['verify_email'] ?? '', 'create_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s'), ]); } // 生成钱包地址 (new UserService())->doRegInitUserInfo($userId, $parentUserId); // 注册聊天账号 $chatData = [ 'Username' => $userNo, 'Password' => '123456', 'Nickname' => $regUser->nick_name, 'Avatar' => env('USER.DEFAULT_HEAD_IMG_PATH'), ]; $chatUrl = env('CHAT_SERVER.BASE_URL') . '/api/user/register'; $chatRes = (new \app\utility\RequestChatServer())->ReqChatServer($chatUrl, $chatData); if (!isset($chatRes['data']['uuid'])) { return $this->toData('500', lang('account_registration_failed')); } // 绑定注册账号与聊天账号 UserChatLinkModel::create([ 'user_id' => $userId, 'user_type' => 1, 'chat_uuid' => $chatRes['data']['uuid'], 'chat_name' => $chatRes['data']['username'] ]); // 如果有代理,绑定到代理下一个客服(轮询客服绑定) if ($agentId > 0 ) { Log::info("手机号注册 - 开始获取客服列表..."); $customerIds = AdminModel::getCustomerIdsByAgentId($agentId); // 获取代理下的所有客服ID Log::info("手机号注册 - 获取客服列表结果==".json_encode($customerIds)); if (empty($customerIds)) { return $this->toData('500', lang('account_registration_failed')); } $counterKey = 'counter_of_bind_customer:'.$agentId; $counterIndex = Cache::store('redis')->get($counterKey); //客服绑定计数器索引 if (empty($counterIndex)) { Cache::store('redis')->set($counterKey, 1); $tagCustomerId = $customerIds[0]; } else { Cache::store('redis')->inc($counterKey); //更新计数器索引 $tagIndex = $counterIndex % count($customerIds); $tagCustomerId = $customerIds[$tagIndex]; } Log::info("手机号注册 - 或者最终绑定客服ID==".$tagCustomerId); if ($tagCustomerId > 0) { $regUser->customer_id = $tagCustomerId; $regUser->save(); } // 将注册账号的chat_id与绑定客服的chat_id加为好友 $customerChatInfo = UserChatLinkModel::where(['user_id'=>$tagCustomerId,'user_type'=>UserChatLinkModel::USER_CHAT_LINK_USER_TYPE_ADMIN])->find(); //查询客服的聊天账号uuid if (empty($customerChatInfo)) { return $this->toData('100400', 'The customer uuid is error.', []); } $chatFriendsData = [ 'UserUuid' => $chatRes['data']['uuid'], 'CustomerUuid' => $customerChatInfo->chat_uuid, ]; $chatFriendsUrl = env('CHAT_SERVER.BASE_URL') . '/api/eachOtherFriends'; $chatFriendsRes = (new \app\utility\RequestChatServer())->ReqChatServer($chatFriendsUrl, $chatFriendsData); Log::info("手机号注册 - chat服务加好友结果:".json_encode($chatFriendsRes)); // 将当前用户加入到代理创建的群聊中 【需要查出当前用户的代理创建的群聊信息】 $agentGroup = UserChatGroupModel::where(['user_id'=>$agentId,'remark'=>UserChatGroupModel::USER_CHAT_GROUP_REMARK_ADMIN_INIT])->find(); if (empty($agentGroup)) { return $this->toData('500', lang('account_registration_failed')); } $joinChatGroupUrl = env('CHAT_SERVER.BASE_URL') . '/api/group/join/'.$chatRes['data']['uuid'].'/'.$agentGroup->group_uuid; $joinChatGroupRes = (new \app\utility\RequestChatServer())->ReqChatServer($joinChatGroupUrl, []); Log::info("手机号注册 - 用户与客服加好友结果:".json_encode($joinChatGroupRes)); } }); // 删除缓存 $this->delCache($smsKey); // 更新注册个数 $this->updateHadRegisterNumCache($ipCanRegisterNumPerIpPerDay); return $this->toData('0', lang('account_registration_successful')); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('100400', $message); } catch (\Exception $exception) { return $this->toData('500', lang('system_busy'), [$exception->getMessage(), $exception->getTrace()]); } } /** * @desc 短信验证码登陆 * @param array $param * @return array * @throws InvalidArgumentException */ public function loginSms(array $param): array { try { // 邮件注册参数校验 validate(LoginValidate::class)->scene('smsLogin')->check($param); $param['nation'] = trim($param['nation']); $param['phone'] = trim($param['phone']); // 验证短信验证码 $mobile = $param['nation'] . $param['phone']; $smsKey = 'DB:USER:UNLOGIN:SMS_CODE:' . $mobile; if ($param['sms_code'] != 8888) { if (!$this->checkCode($smsKey, $param['sms_code'])) { return $this->toData('500', lang('incorrect_verification_code')); }; } // 查找手机号 $userId = UserModel::getUserIdByNationAndPhone($param['nation'], $param['phone']); if ($userId <= 0) { return $this->toData('500', lang('user_does_not_exist')); } // 查找用户信息 $user = UserModel::getFieldsByUserId('invite_code,user_id,user_no,nick_name,is_real,login_password,salt', $userId); if (empty($user)) { return $this->toData('500', lang('user_does_not_exist')); } // 生成token $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); if (empty($token)) { return $this->toData('500', lang('system_busy')); } // 用户登陆之后需要进行的操作 异步完成 Queue::push('app\home\job\LoginDone', ['userId' => $userId, 'fields' => [ 'last_login_time' => date('Y-m-d H:i:s'), 'ip' => $this->getClientRealIp(), 'device' => $param['device'], ] ], 'loginDone'); // 将token存致缓存 覆盖新的缓存 实现单设备登陆 $this->setUserTokenCache($token, $userId); // 用户登记关系 (new UserService())->getUserLevel($userId); // 返回结果以及用户信息 return $this->toData('0', 'Request successful.', [ 'userId' => $userId, 'userNo' => $user['user_no'], 'nickName' => $user['nick_name'], 'isReal' => $user['is_real'], 'inviteCode' => $user['invite_code'], 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), 'token' => $token, ]); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('100400', $message); } catch (\Exception $exception) { return $this->toData('500', lang('system_busy'), [$exception->getMessage(), $exception->getTrace()]); } } /** * @desc 忘记密码 根据邮箱设置密码 * @param array $param * @return array * @throws InvalidArgumentException */ public function resetPasswordByEmail(array $param): array { try { // 邮件注册参数校验 validate(LoginValidate::class)->scene('emailForget')->check($param); // 验证码 $emailKey = 'DB:USER:UNLOGIN:EMAIL_CODE:' . $param['email']; if (!$this->checkCode($emailKey, $param['email_code'])) { return $this->toData('500', lang('incorrect_verification_code')); } // 查找邮箱 $userId = UserModel::getUserIdByEmail($param['email']); if ($userId <= 0) { return $this->toData('500', lang('user_does_not_exist')); } // 修改密码 $salt = env('ENCRYPT.SALT'); $password = (new UnqId())->encryptPassword($param['password'], $salt); UserModel::updatePassword($password, $salt, $userId); // 删除缓存 $this->delCache($emailKey); return $this->toData('0', 'Modification successful.', []); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('100400', $message); } catch (\Exception $exception) { return $this->toData('100500', lang('system_busy'), [$exception->getMessage(), $exception->getTrace()]); } } /** * @desc 忘记密码 根据短信设置密码 * @param array $param * @return array * @throws InvalidArgumentException */ public function resetPasswordBySms(array $param): array { try { // 邮件注册参数校验 validate(LoginValidate::class)->scene('smsForget')->check($param); // 判断验证码 $mobile = $param['nation'] . $param['phone']; $smsKey = 'DB:USER:UNLOGIN:SMS_CODE:' . $mobile; if (!$this->checkCode($smsKey, $param['sms_code'])) { return $this->toData('500', lang('incorrect_verification_code')); } // 查找用户 $userId = UserModel::getUserIdByNationAndPhone($param['nation'], $param['phone']); if ($userId <= 0) { return $this->toData('500', lang('user_does_not_exist')); } // 修改密码 $salt = env('ENCRYPT.SALT'); $password = (new UnqId())->encryptPassword($param['password'], $salt); UserModel::updatePassword($password, $salt, $userId); // 删除缓存 $this->delCache($smsKey); return $this->toData('0', 'Modification successful.', []); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('100400', $message); } catch (\Exception $exception) { return $this->toData('500', lang('system_busy'), [$exception->getMessage(), $exception->getTrace()]); } } /** * @desc 手机号 密码登陆 * @param $param * @return array */ public function phoneLogin($param): array { try { // 参数校验 validate(LoginValidate::class)->scene('smsPasswordLogin')->check($param); // 获取用户 $userId = UserModel::getUserIdByNationAndPhone($param['nation'], $param['phone']); if ($userId <= 0) { return $this->toData('500', lang('user_does_not_exist')); } $info = UserModel::getFieldsByUserId('invite_code,is_real,nick_name,user_no,user_id,login_password,salt', $userId); if (empty($info)) { return $this->toData('500', lang('user_does_not_exist')); } // 校验密码 $checkPasswordBool = (new UnqId())->checkPassword($param['password'], $info['login_password'], $info['salt']); if (!$checkPasswordBool) { return $this->toData('500', lang('incorrect_account_or_password')); } // 生成token $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); if (empty($token)) { return $this->toData('500', lang('system_busy')); } // 用户登陆之后需要进行的操作 异步完成 Queue::push('app\home\job\LoginDone', ['userId' => $userId, 'fields' => [ 'last_login_time' => date('Y-m-d H:i:s'), 'ip' => $this->getClientRealIp(), 'device' => $param['device'], ] ], 'loginDone'); // 将token存致缓存 覆盖新的缓存 实现单设备登陆 $this->setUserTokenCache($token, $userId); // 用户登记关系 (new UserService())->getUserLevel($userId); // 返回结果以及用户信息 return $this->toData('0', 'Request successful.', [ 'userId' => $userId, 'userNo' => $info['user_no'], 'nickName' => $info['nick_name'], 'isReal' => $info['is_real'], 'inviteCode' => $info['invite_code'], 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), 'token' => $token, ]); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('100400', $message); } catch (\Exception $exception) { return $this->toData('500', lang('system_busy')); } } public function autoLogin($param): array { try { $login_token=$param['login_token']; $tokenUserKey = 'AUTO:TOKEN:'.$login_token; $userId = Cache::store('redis')->get($tokenUserKey); if(empty($userId) || $userId <= 0){ return $this->toData('500', 'Incorrect token', []); } $info = UserModel::getFieldsByUserId('invite_code,is_real,nick_name,user_no,user_id,login_password,salt', $userId); if (empty($info)) { return $this->toData('500', lang('user_does_not_exist')); } // 生成token $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); if (empty($token)) { return $this->toData('500', lang('system_busy'), []); } // 将token存致缓存 覆盖新的缓存 实现单设备登陆 $this->setUserTokenCache($token, $userId); // 用户登记关系 (new UserService())->getUserLevel($userId); // 返回结果以及用户信息 return $this->toData('0', 'Request successful.', [ 'userId' => $userId, 'userNo' => $info['user_no'], 'nickName' => $info['nick_name'], 'isReal' => $info['is_real'], 'inviteCode' => $info['invite_code'], 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), 'token' => $token, ]); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('100400', $message); } catch (\Exception $exception) { return $this->toData('500', lang('system_busy')); } } public function testLogin($param): array { try { $login_token=$param['login_token']; $tokenUserKey = 'AUTO:TOKEN:'.$login_token; $userId = Cache::store('redis')->get($tokenUserKey); if(empty($userId) || $userId <= 0){ return $this->toData('100300', 'Incorrect token', []); } $info = UserModel::getFieldsByUserId('invite_code,is_real,nick_name,user_no,user_id,login_password,salt', $userId); if (empty($info)) { return $this->toData('100300', 'Incorrect account or password.2', []); } // 生成token $token = (new Jwt())->getToken($userId, env('ENCRYPT.SALT')); if (empty($token)) { return $this->toData('500', lang('system_busy')); } // 将token存致缓存 覆盖新的缓存 实现单设备登陆 $this->setUserTokenCache($token, $userId); // 用户登记关系 (new UserService())->getUserLevel($userId); // 返回结果以及用户信息 return $this->toData('0', 'Request successful.', [ 'userId' => $userId, 'userNo' => $info['user_no'], 'nickName' => $info['nick_name'], 'isReal' => $info['is_real'], 'inviteCode' => $info['invite_code'], 'logo' => env('USER.DEFAULT_HEAD_IMG_PATH'), 'token' => $token, ]); } catch (ValidateException $validateException) { // 参数校验失败 异常类 $message = $validateException->getError(); return $this->toData('100400', $message); } catch (\Exception $exception) { return $this->toData('500', lang('system_busy'), []); } } public function getIP(): array { $ip=$this->getClientRealIp(); $countryDb = base_path().'GeoLite2-Country.mmdb'; $cityDb = base_path().'GeoLite2-City.mmdb'; $countryReader = new Reader($countryDb); $cityReader = new Reader($cityDb); try{ $countryNames = $countryReader->country($ip)->country->names; $cityNames = $cityReader->city($ip)->city->names; return $this->toData('0', 'Request successful.', [ 'country' => $countryNames['zh-CN'], 'city' => $cityNames['zh-CN'], 'ip'=>$ip ]); }catch (\Exception $exception){ return $this->toData('0', 'Request successful.', [ 'country' => '未知', 'city' =>'未知', 'ip'=>$ip ]); } } }