手机号登录增强:规范化手机号并支持重发验证码
This commit is contained in:
1 parent
e4cfab891b
commit
8c2499e988
3 files changed
+88
-8
No files matched your search
@@ -17,6 +17,11 @@ public interface IAccountService
|
||||
/// </summary>
|
||||
Task<LoginResult> SubmitCodeAsync(int accountId, string code);
|
||||
|
||||
/// <summary>
|
||||
/// 重新发送验证码(可能切换到短信/电话等其它通道,取决于 Telegram 策略)
|
||||
/// </summary>
|
||||
Task<LoginResult> ResendCodeAsync(int accountId);
|
||||
|
||||
/// <summary>
|
||||
/// 提交两步验证密码
|
||||
/// </summary>
|
||||
|
||||
@@ -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<LoginResult> 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<char> 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]);
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,12 @@
|
||||
<MudTextField @bind-Value="verificationCode" Label="验证码" Variant="Variant.Outlined" Required="true"
|
||||
Placeholder="12345" />
|
||||
<MudText Typo="Typo.caption" Class="mt-2" Color="Color.Info">
|
||||
请在Telegram客户端查收验证码
|
||||
说明:验证码通常优先发送到已登录设备的 Telegram「系统通知(777000)」;没有可用设备时才可能发送短信/电话。
|
||||
</MudText>
|
||||
<MudButton Variant="Variant.Outlined" Color="Color.Secondary" Class="mt-3"
|
||||
Disabled="@logging" OnClick="@(async (MouseEventArgs _) => await ResendCodeAsync())">
|
||||
重新发送验证码(尝试切换通道)
|
||||
</MudButton>
|
||||
</MudStep>
|
||||
|
||||
<MudStep Title="密码验证" Optional="true">
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user