Pyrogram输入OTP及时却提示过期的问题修复请求
问题描述
我现在碰到一个特别棘手的问题:明明在收到Telegram的OTP后几秒内就输入提交了,系统却一直弹出错误提示**"The confirmation code has expired. Request a new one."**。我怀疑是Pyrogram库存在bug,或者我代码里有没注意到的细节问题,试了好几种验证OTP的方式都没解决,麻烦帮忙看看怎么修复,谢谢!
核心实现代码
下面是我实现Telegram认证流程的核心代码:
class TelegramWorker(QThread): otp_sent = pyqtSignal(object) auth_complete = pyqtSignal(bool, str) def __init__(self, action, phone_number=None, otp=None, phone_code_hash=None, password=None): super().__init__() self.action = action self.phone_number = phone_number self.otp = otp self.phone_code_hash = phone_code_hash self.password = password self.client = None def run(self): asyncio.run(self.perform_action()) async def perform_action(self): try: self.client = Client(TELEGRAM_SESSION, api_id=API_ID, api_hash=API_HASH) await self.client.connect() if self.action == "send_code": sent_code_info = await self.client.send_code(self.phone_number) self.otp_sent.emit(sent_code_info) elif self.action == "auth_with_otp": try: await self.client.sign_in( self.phone_number, self.phone_code_hash, self.otp ) self.auth_complete.emit(True, "Authentication successful!") except errors.PhoneCodeInvalid: self.auth_complete.emit(False, "Invalid confirmation code. Please try again.") except errors.PhoneCodeExpired: self.auth_complete.emit(False, "The confirmation code has expired. Request a new one.") elif self.action == "auth_with_password": await self.client.check_password(self.password) self.auth_complete.emit(True, "Authentication successful!") await self.client.disconnect() except errors.SessionPasswordNeeded: self.auth_complete.emit(False, "Password is required for authentication.") except Exception as e: self.auth_complete.emit(False, str(e)) class TelegramAuthenticationDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle("Telegram Authentication") self.setFixedSize(400, 300) self.phone_number = None self.sent_code = None self.worker = None self.resend_timer = QTimer(self) # Add a QTimer for resending OTP self.resend_timer.timeout.connect(self.update_resend_timer) self.resend_countdown = 60 self.init_ui() def init_ui(self): --- relevant UI code--- def authenticate(self): otp = self.otp_input.text().strip() if not otp: QMessageBox.information(self, "Error", "Enter the OTP.") return self.worker = TelegramWorker(action="auth_with_otp", phone_number=self.phone_number, otp=otp, phone_code_hash=self.sent_code.phone_code_hash) self.worker.auth_complete.connect(self.handle_auth_result) self.worker.start() def handle_auth_result(self, success, message): if success: QMessageBox.information(self, "Success", message) self.accept() else: QMessageBox.warning(self, "Error", message) if "password" in message.lower(): self.password_input.setVisible(True) self.otp_input.setVisible(False) self.action_button.setText("Authenticate with Password") self.action_button.clicked.disconnect() self.action_button.clicked.connect(self.authenticate_with_password) elif "expired" in message.lower() or "invalid" in message.lower(): self.otp_input.clear() self.action_button.setText("Send OTP on Telegram") self.action_button.clicked.disconnect() self.action_button.clicked.connect(self.send_otp) self.otp_input.setVisible(False) self.resend_label.setVisible(False) def authenticate_with_password(self): password = self.password_input.text().strip() if not password: QMessageBox.information(self, "Error", "Enter your Telegram password.") return self.worker = TelegramWorker(action="auth_with_password", password=password) self.worker.auth_complete.connect(self.handle_auth_result) self.worker.start() def start_resend_timer(self): self.resend_countdown = 180 self.resend_label.setText(f"Didn't receive OTP? Resend in {self.resend_countdown} seconds") self.resend_timer.start(1000) def update_resend_timer(self): self.resend_countdown -= 1 if self.resend_countdown <= 0: self.resend_timer.stop() self.resend_label.setText("Didn't receive OTP? Resend") self.action_button.setText("Resend OTP") self.action_button.clicked.disconnect() self.action_button.clicked.connect(self.resend_otp) else: self.resend_label.setText(f"Didn't receive OTP? Resend in {self.resend_countdown} seconds") def resend_otp(self): self.resend_label.setVisible(False) self.otp_input.clear() self.otp_input.setVisible(False) self.send_otp()
排查与修复建议
我梳理了几个高概率的问题点,你可以逐一尝试:
会话文件冲突问题
你当前的TELEGRAM_SESSION是固定文件名,可能存在不同手机号会话残留的干扰。试试把会话文件名和手机号绑定,比如改成f"telegram_session_{self.phone_number}",确保每个手机号的会话独立。OTP格式处理问题
Telegram发送的OTP可能带有空格(比如123 456),如果直接传递带空格的字符串给sign_in就会触发错误。在authenticate方法里加一行格式处理:otp = otp.replace(" ", "").strip()Pyrogram版本兼容问题
旧版本Pyrogram可能存在OTP验证的bug,试试升级到最新稳定版:pip install --upgrade pyrogram tgcrypto参数传递准确性验证
确认self.sent_code确实完整保存了send_code返回的sent_code_info对象,没有在传递过程中丢失phone_code_hash的正确值。可以在auth_with_otp分支里打印参数,确认phone_code_hash和OTP都是正确的。异步线程调度问题
用QThread跑异步任务时,可能存在调度延迟导致请求发送不及时。可以在perform_action的auth_with_otp块里添加时间戳打印,确认请求是在OTP有效期内发送的。
先从这几个方向排查,尤其是会话文件和OTP格式的问题,大概率能解决你的问题!
备注:内容来源于stack exchange,提问作者Madhusudan Mishra

