parseEquipment(); $browser = $ua->parseBrowser(); $userModel = AdminModel::with(['role:id,name,value'])->where('phone', $phone)->first(); if (empty($userModel)) { $this->writeLoginLog(0, (string) $phone, '', 1, '用户或密码错误', $equipment, $browser); UtilsService::getInstance()->errorThrow('用户或密码错误!'); } if (!password_verify($password, $userModel->password)) { $this->writeLoginLog( (int) $userModel->id, (string) $phone, (string) $userModel->nick_name, 1, '用户或密码错误', $equipment, $browser ); UtilsService::getInstance()->errorThrow('用户或密码错误!'); } $updateData = [ 'last_login_time' => get_time(), 'updated_at' => get_time(), ]; if ($userModel->ip !== get_ip()) { $ipTable = json_decode($userModel->ip_table, true); if (!in_array(get_ip(), $ipTable ?? [])) { $ipTable[] = get_ip(); } $updateData['ip'] = get_ip(); $updateData['ip_table'] = json_encode($ipTable); } $update = AdminModel::where('id', $userModel->id)->update($updateData); if (!$update) { $this->writeLoginLog( (int) $userModel->id, (string) $phone, (string) $userModel->nick_name, 1, '更新登录信息失败', $equipment, $browser ); UtilsService::getInstance()->errorThrow('更新失败!'); } $userModel = AdminModel::with(['role:id,name,value'])->where('id', $userModel->id)->first(); $this->writeLoginLog( (int) $userModel->id, (string) $userModel->phone, (string) $userModel->nick_name, 0, '登录成功', $equipment, $browser ); $result = [ 'id' => $userModel->id, 'phone' => $userModel->phone, 'nick_name' => $userModel->nick_name, 'avatar' => $userModel->avatar, 'email' => $userModel->email, 'role_id' => $userModel->role_id, 'role_name' => $userModel->role->name, 'role_value' => $userModel->role->value, 'ip' => $userModel->ip, 'ip_table' => $userModel->ip_table, ]; $token = JWTService::getInstance()->generateToken($result); $result['token'] = $token; return $result; } /** * 注册管理员账号 * * @param string $phone 手机号 * @param string $password 密码 * @param string $email 邮箱 * @param mixed $code 验证码(预留) * @return array * @throws Exception */ public function register($phone, $password, $email, $code): array { $userModel = AdminModel::where('phone', $phone)->first(); if ($userModel) { UtilsService::getInstance()->errorThrow('账号已被占用!'); } $createModel = AdminModel::create([ 'phone' => $phone, 'email' => $email, 'password' => password_hash($password, PASSWORD_DEFAULT), 'nick_name' => '新用户' . Str::random(), 'avatar' => 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280', 'role_id' => 2, 'ip' => get_ip(), 'ip_table' => json_encode([get_ip()]), 'created_at' => get_time(), ]); if (!$createModel) { UtilsService::getInstance()->errorThrow('注册失败!'); } $userInfo = AdminModel::with(['role:id,name,value'])->where('id', $createModel->id)->first(); $result = [ 'id' => $userInfo->id, 'phone' => $userInfo->phone, 'nick_name' => $userInfo->nick_name, 'avatar' => $userInfo->avatar, 'email' => $userInfo->email ?? '', 'role_name' => $userInfo->role->name, 'role_value' => $userInfo->role->value, 'ip' => $userInfo->ip, 'ip_table' => $userInfo->ip_table, ]; $token = JWTService::getInstance()->generateToken($result); $result['token'] = $token; return $result; } /** * 写入登录日志(失败也尽量落库,内部吞异常避免掩盖业务错误) * * @param int $userId 管理员 ID,失败未知用户可为 0 * @param string $phone 登录账号 * @param string $nickName 昵称快照 * @param int $status 0成功 1失败 * @param string $message 结果说明 * @param string $equipment 操作系统 * @param string $browser 浏览器 */ private function writeLoginLog( int $userId, string $phone, string $nickName, int $status, string $message, string $equipment, string $browser ): void { try { LoginLogModel::insert([ 'user_id' => $userId, 'phone' => $phone, 'nick_name' => $nickName, 'ip' => (string) get_ip(), 'equipment' => $equipment, 'browser' => $browser, 'status' => $status, 'message' => $message, 'created_at' => time(), ]); } catch (\Throwable $e) { // 日志失败不影响登录主流程 } } }