diff --git a/src/TelegramPanel.Core/Interfaces/IAccountService.cs b/src/TelegramPanel.Core/Interfaces/IAccountService.cs index 617fbb8..84f7113 100644 --- a/src/TelegramPanel.Core/Interfaces/IAccountService.cs +++ b/src/TelegramPanel.Core/Interfaces/IAccountService.cs @@ -17,6 +17,11 @@ public interface IAccountService /// Task SubmitCodeAsync(int accountId, string code); + /// + /// 重新发送验证码(可能切换到短信/电话等其它通道,取决于 Telegram 策略) + /// + Task ResendCodeAsync(int accountId); + /// /// 提交两步验证密码 /// diff --git a/src/TelegramPanel.Core/Services/Telegram/AccountService.cs b/src/TelegramPanel.Core/Services/Telegram/AccountService.cs index f5281ab..dad6fa9 100644 --- a/src/TelegramPanel.Core/Services/Telegram/AccountService.cs +++ b/src/TelegramPanel.Core/Services/Telegram/AccountService.cs @@ -36,20 +36,21 @@ public class AccountService : IAccountService var apiHash = _configuration["Telegram:ApiHash"]!.Trim(); var sessionsPath = _configuration["Telegram:SessionsPath"] ?? "sessions"; Directory.CreateDirectory(sessionsPath); - var sessionPath = Path.Combine(sessionsPath, $"{phone}.session"); + var normalizedPhone = NormalizePhoneForLogin(phone); + var sessionPath = Path.Combine(sessionsPath, $"{normalizedPhone}.session"); // 若已有旧的 SQLite 格式 session(Telethon/Pyrogram/Telegram Desktop 常见),会导致 WTelegramClient 直接读取失败, // 这里先自动备份,确保“手机号登录”能顺利重新生成 WTelegram 的 session。 TryBackupSqliteSessionIfExists(sessionPath); - _logger.LogInformation("Starting login for phone {Phone}", phone); + _logger.LogInformation("Starting login for phone {Phone}", normalizedPhone); - var client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, sessionPath, sessionKey: apiHash, phoneNumber: phone, userId: null); + var client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, sessionPath, sessionKey: apiHash, phoneNumber: normalizedPhone, userId: null); string result; try { - result = await client.Login(phone); + result = await client.Login(normalizedPhone); } catch (Exception ex) when (LooksLikeSessionApiMismatchOrCorrupted(ex)) { @@ -57,20 +58,42 @@ public class AccountService : IAccountService TryBackupCorruptedSessionIfExists(sessionPath); await _clientPool.RemoveClientAsync(accountId); - client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, sessionPath, sessionKey: apiHash, phoneNumber: phone, userId: null); - result = await client.Login(phone); + client = await _clientPool.GetOrCreateClientAsync(accountId, apiId, apiHash, sessionPath, sessionKey: apiHash, phoneNumber: normalizedPhone, userId: null); + result = await client.Login(normalizedPhone); } + _logger.LogInformation("Login flow next step for {Phone}: {Step}", normalizedPhone, result); + return result switch { "verification_code" => new LoginResult(false, "code", "请输入验证码"), "password" => new LoginResult(false, "password", "请输入两步验证密码"), "name" => new LoginResult(false, "signup", "需要注册新账号"), + "email" => new LoginResult(false, "email", "该账号需要邮箱验证(请按提示填写邮箱并完成验证)"), + "email_verification_code" => new LoginResult(false, "email_code", "请输入邮箱验证码"), _ when client.User != null => new LoginResult(true, null, "登录成功", MapToAccountInfo(accountId, client)), _ => new LoginResult(false, null, $"未知状态: {result}") }; } + public async Task ResendCodeAsync(int accountId) + { + var client = _clientPool.GetClient(accountId) + ?? throw new InvalidOperationException($"Client not found for account {accountId}"); + + // WTelegram 约定:verification_code 提交空字符串会触发“通过另一种方式重发验证码”(短信/电话等) + var result = await client.Login(string.Empty); + _logger.LogInformation("Resend code requested for temp account {AccountId}, next step: {Step}", accountId, result); + + return result switch + { + "verification_code" => new LoginResult(false, "code", "已请求重新发送验证码"), + "password" => new LoginResult(false, "password", "需要两步验证密码"), + _ when client.User != null => new LoginResult(true, null, "登录成功", MapToAccountInfo(accountId, client)), + _ => new LoginResult(false, null, $"重新发送失败:{result}") + }; + } + private static bool LooksLikeSessionApiMismatchOrCorrupted(Exception ex) { var msg = ex.Message ?? string.Empty; @@ -146,6 +169,7 @@ public class AccountService : IAccountService var client = _clientPool.GetClient(accountId) ?? throw new InvalidOperationException($"Client not found for account {accountId}"); + code = (code ?? string.Empty).Trim(); var result = await client.Login(code); return result switch @@ -221,4 +245,26 @@ public class AccountService : IAccountService LastActiveAt = DateTime.UtcNow }; } + + private static string NormalizePhoneForLogin(string phone) + { + phone = (phone ?? string.Empty).Trim(); + if (phone.StartsWith("+", StringComparison.Ordinal)) + phone = phone[1..]; + if (phone.StartsWith("00", StringComparison.Ordinal)) + phone = phone[2..]; + + Span buf = stackalloc char[phone.Length]; + var n = 0; + foreach (var ch in phone) + { + if (ch is >= '0' and <= '9') + buf[n++] = ch; + } + + if (n == 0) + throw new ArgumentException("手机号格式不正确,请包含国家代码(例如:+8613800138000)", nameof(phone)); + + return new string(buf[..n]); + } } diff --git a/src/TelegramPanel.Web/Components/Pages/AccountLogin.razor b/src/TelegramPanel.Web/Components/Pages/AccountLogin.razor index f30b4c0..9104e85 100644 --- a/src/TelegramPanel.Web/Components/Pages/AccountLogin.razor +++ b/src/TelegramPanel.Web/Components/Pages/AccountLogin.razor @@ -45,8 +45,12 @@ - 请在Telegram客户端查收验证码 + 说明:验证码通常优先发送到已登录设备的 Telegram「系统通知(777000)」;没有可用设备时才可能发送短信/电话。 + + 重新发送验证码(尝试切换通道) + @@ -173,7 +177,7 @@ } // 生成临时账号ID(用于跟踪登录过程) - accountId = DateTime.UtcNow.GetHashCode(); + accountId = Random.Shared.Next(1, int.MaxValue); var result = await AccountService.StartLoginAsync(accountId, phoneNumber); @@ -248,6 +252,31 @@ } } + private async Task ResendCodeAsync() + { + if (logging) return; + if (accountId == 0) + { + Snackbar.Add("请先在上一步发送验证码", Severity.Warning); + return; + } + + logging = true; + try + { + var result = await AccountService.ResendCodeAsync(accountId); + Snackbar.Add(result.Message ?? "已请求重新发送验证码", result.Success ? Severity.Success : Severity.Info); + } + catch (Exception ex) + { + Snackbar.Add($"重新发送失败:{ex.Message}", Severity.Error); + } + finally + { + logging = false; + } + } + private async Task SaveAccount(TelegramPanel.Core.Models.AccountInfo accountInfo) { try