You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 18:45:59