Telethon开发Telegram Bot时验证码登录失败问题求助
Telegram登录验证码验证失败问题排查
我用Telethon开发Telegram Bot,Bot需要访问账户多个聊天会话并把消息解析存入数据库。登录时Telegram发了验证码,但把验证码发给Bot后验证失败,提示:
无人获取到您的聊天权限,因为登录未完成。验证码输入正确,但登录未被允许,因为该验证码已被您的账户共享过。请勿向他人分享登录验证码,因为这会允许任何人登录您的账户并访问聊天内容。
已经关闭了2FA,但问题依旧,求排查代码问题。
原身份验证代码片段
async def handle_app_info(bot, event): global app_state, last_message_id user_id = event.message.peer_id.user_id response = event.message.text parts = response.split() if len(parts) != 4: error_message = "Error: Invalid input format. Please provide all required information." await bot.send_message(user_id, error_message) return phone_number, app_id, app_hash, app_name = parts client = TelegramClient(StringSession(), app_id, app_hash) await client.connect() if not await client.is_user_authorized(): await client.send_code_request(phone_number) message = "Please enter the code sent to your Telegram app:" await bot.send_message(user_id, message) # Set user state to WAITING_CODE db.set_user_state(user_id, states.WAITING_CODE) # Set user state to WAITING_CODE app_state = AppState.WAITING_CODE last_message_id = event.message.id # Store the client object and phone number in the respective dictionaries clients[user_id] = client phone_numbers[user_id] = phone_number app_ids[user_id] = app_id app_hashes[user_id] = app_hash app_names[user_id] = app_name async def handle_code(bot, event): global app_state, last_message_id user_id = event.message.peer_id.user_id # Handle code input by the user code = event.message.text # Retrieve the client object and phone number from the respective dictionaries client = clients[user_id] phone_number = phone_numbers[user_id] app_id = app_ids[user_id] app_hash = app_hashes[user_id] app_name = app_names[user_id] # Sign in the user with the code they provided try: await client.sign_in(phone_number, code) except Exception as e: await bot.send_message(user_id, f"Failed to sign in: {e}") return # Save the session string session_string = client.session.save() # Save all connection data to the database db.save_connection_data(user_id, phone_number, app_id, app_hash, app_name, session_string) message = "Your Telegram app has been successfully connected to the bot." await bot.send_message(user_id, message) # Reset user state app_state = AppState.MAIN_MENU last_message_id = event.message.id # Reset user state db.set_user_state(user_id, states.MAIN_MENU)
问题根源及修复方案
1. 核心问题点
- 全局状态冲突:
app_state和last_message_id是全局变量,多用户操作或单个用户重复触发流程时,会覆盖之前的状态和会话,导致验证码关联错误。 - 缺失
phone_code_hash:send_code_request会返回包含phone_code_hash的验证信息,登录时必须携带该哈希值,否则会触发验证码验证失败。 - 无重复操作拦截:用户在等待验证码阶段重复提交app信息,会生成新的验证码,旧验证码失效后再输入就会触发“验证码已共享”提示。
2. 修复后的关键代码调整
修改handle_app_info,保存验证码哈希并拦截重复操作
async def handle_app_info(bot, event): user_id = event.message.peer_id.user_id response = event.message.text parts = response.split() if len(parts) != 4: await bot.send_message(user_id, "Error: Invalid input format. Please provide all required information.") return # 拦截等待验证码阶段的重复提交 current_state = db.get_user_state(user_id) if current_state == states.WAITING_CODE: await bot.send_message(user_id, "Please enter the verification code that was already sent to your Telegram app.") return phone_number, app_id, app_hash, app_name = parts client = TelegramClient(StringSession(), app_id, app_hash) await client.connect() if not await client.is_user_authorized(): # 保存验证码请求返回的哈希值 code_result = await client.send_code_request(phone_number) await bot.send_message(user_id, "Please enter the code sent to your Telegram app:") # 更新用户状态并存储验证码哈希 db.set_user_state(user_id, states.WAITING_CODE) db.save_phone_code_hash(user_id, code_result.phone_code_hash) # 存储用户专属的客户端信息 clients[user_id] = client phone_numbers[user_id] = phone_number app_ids[user_id] = app_id app_hashes[user_id] = app_hash app_names[user_id] = app_name
修改handle_code,使用验证码哈希完成登录
async def handle_code(bot, event): user_id = event.message.peer_id.user_id code = event.message.text.strip() # 获取用户专属的客户端、手机号和验证码哈希 client = clients.get(user_id) phone_number = phone_numbers.get(user_id) phone_code_hash = db.get_phone_code_hash(user_id) if not client or not phone_number or not phone_code_hash: await bot.send_message(user_id, "Please re-submit your app information first.") db.set_user_state(user_id, states.MAIN_MENU) return try: # 携带验证码哈希完成登录 await client.sign_in(phone_number=phone_number, code=code, phone_code_hash=phone_code_hash) except Exception as e: await bot.send_message(user_id, f"Failed to sign in: {str(e)}") # 登录失败后重置状态并清理临时数据 db.set_user_state(user_id, states.MAIN_MENU) del clients[user_id] db.delete_phone_code_hash(user_id) return # 持久化会话信息 session_string = client.session.save() db.save_connection_data(user_id, phone_number, app_ids[user_id], app_hashes[user_id], app_names[user_id], session_string) await bot.send_message(user_id, "Your Telegram app has been successfully connected to the bot.") # 重置状态并清理临时哈希 db.set_user_state(user_id, states.MAIN_MENU) db.delete_phone_code_hash(user_id)
3. 额外注意事项
- 移除全局状态变量:完全依赖数据库存储每个用户的独立状态,避免多用户操作冲突。
- 会话持久化:后续可直接用存储的
session_string重建客户端,无需重复登录流程。 - 验证码有效期处理:用户长时间未输入验证码时,需允许重新触发验证码发送,并清理旧的哈希值。
内容的提问来源于stack exchange,提问作者Fiodar Pazhyvilka
相关产品推荐
相关产品推荐

