using HaloPixelToolBox.Backend.Profiles.CacheProfiles;
using HaloPixelToolBox.Backend.Profiles.CrossVersionProfiles;
using HaloPixelToolBox.Core.Models.User;
using HaloPixelToolBox.Core.Utilities;
using System.Net;
using XFEExtension.NetCore.ServerInteractive.Models.RequesterModels;
namespace HaloPixelToolBox.Backend.Utilities;
/// <summary>
/// 统一维护管理端登录状态,并负责启动时恢复或重新创建管理员会话。
/// </summary>
public static class AdministratorSessionManager
{
private static readonly SemaphoreSlim s_authenticationLock = new(1, 1);
public static event EventHandler? StateChanged;
public static MyUserFaceInfo? CurrentUser { get; private set; }
public static bool IsLoggedIn { get; private set; }
public static bool IsBusy { get; private set; }
public static string StatusText { get; private set; } = "正在准备自动登录...";
public static string DisplayName => CurrentUser?.NickName ?? (IsLoggedIn ? CacheProfile.Account : "未登录");
/// <summary>
/// 优先恢复现有会话;会话失效时,使用本机保存的账号密码自动重新登录。
/// </summary>
public static async Task<bool> InitializeAsync(bool forceReconnect = false)
{
await s_authenticationLock.WaitAsync();
try
{
if (IsLoggedIn && !forceReconnect)
return true;
SetBusy(true, forceReconnect ? "正在重新连接服务器..." : "正在自动登录...");
if (!await ConnectAsync(forceReconnect))
{
SetLoggedOut("服务器连接失败,请在设置中检查服务器地址");
return false;
}
if (!string.IsNullOrWhiteSpace(CacheProfile.Session))
{
DataManager.ClientRequester.Session = CacheProfile.Session;
var restoredUser = await RestoreSessionCoreAsync();
if (restoredUser is not null)
{
CompleteLogin(restoredUser, CacheProfile.Session, "已自动恢复登录");
return true;
}
ClearSession();
StatusText = "登录会话已过期,正在使用保存的凭据重新登录...";
NotifyStateChanged();
}
if (string.IsNullOrWhiteSpace(CacheProfile.Account) || string.IsNullOrWhiteSpace(CacheProfile.Password))
{
SetLoggedOut("请输入管理员账号和密码,成功后将自动登录");
return false;
}
return await LoginCoreAsync(CacheProfile.Account, CacheProfile.Password, "已自动登录");
}
catch (Exception ex)
{
SetLoggedOut($"自动登录失败:{ex.Message}");
return false;
}
finally
{
SetBusy(false);
s_authenticationLock.Release();
}
}
/// <summary>
/// 使用用户输入的管理员凭据登录,并在成功后保存用于下次自动登录。
/// </summary>
public static async Task<bool> LoginAsync(string account, string password)
{
account = account.Trim();
if (string.IsNullOrWhiteSpace(account) || string.IsNullOrWhiteSpace(password))
{
SetLoggedOut("请输入管理员账号和密码");
return false;
}
await s_authenticationLock.WaitAsync();
try
{
SetBusy(true, "正在登录管理员账号...");
if (!await ConnectAsync(true))
{
SetLoggedOut("服务器连接失败,请在设置中检查服务器地址");
return false;
}
return await LoginCoreAsync(account, password, "已登录");
}
catch (Exception ex)
{
SetLoggedOut($"登录失败:{ex.Message}");
return false;
}
finally
{
SetBusy(false);
s_authenticationLock.Release();
}
}
/// <summary>
/// 退出管理端,并清除本机保存的密码,防止随后再次自动登录。
/// </summary>
public static async Task LogoutAsync()
{
await s_authenticationLock.WaitAsync();
try
{
ClearSession();
CacheProfile.Password = string.Empty;
SetLoggedOut("已退出登录;下次需要重新输入密码");
}
finally
{
s_authenticationLock.Release();
}
}
private static async Task<bool> ConnectAsync(bool forceReconnect)
{
var serverAddress = SystemProfile.ServerAddress.Trim();
if (!Uri.TryCreate(serverAddress, UriKind.Absolute, out var uri) ||
(uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps))
{
StatusText = "服务器地址无效,请输入完整的 HTTP 或 HTTPS 地址";
NotifyStateChanged();
return false;
}
return await DataManager.InitializeAsync([serverAddress], forceReconnect);
}
private static async Task<MyUserFaceInfo?> RestoreSessionCoreAsync()
{
var response = await DataManager.ClientRequester.Request<MyUserFaceInfo>("relogin");
return response.StatusCode == HttpStatusCode.OK && IsAdministrator(response.Result)
? response.Result
: null;
}
private static async Task<bool> LoginCoreAsync(string account, string password, string successMessage)
{
ClearSession();
var response = await DataManager.ClientRequester.Request<UserLoginResult<MyUserFaceInfo>>("login", account, password);
if (response.StatusCode != HttpStatusCode.OK || response.Result?.UserInfo is null)
{
SetLoggedOut("登录失败,请检查账号或密码");
return false;
}
if (!IsAdministrator(response.Result.UserInfo))
{
ClearSession();
SetLoggedOut("该账号没有管理员权限");
return false;
}
CacheProfile.Account = account;
CacheProfile.Password = password;
CompleteLogin(response.Result.UserInfo, response.Result.Session, successMessage);
return true;
}
private static bool IsAdministrator(MyUserFaceInfo? user) =>
user is not null && user.PermissionLevel >= (int)UserRole.管理员;
private static void CompleteLogin(MyUserFaceInfo user, string session, string successMessage)
{
DataManager.ClientRequester.Session = session;
CacheProfile.Session = session;
CurrentUser = user;
IsLoggedIn = true;
StatusText = $"{successMessage}:{user.NickName}({(UserRole)user.PermissionLevel})";
NotifyStateChanged();
}
private static void ClearSession()
{
DataManager.ClientRequester.Session = string.Empty;
CacheProfile.Session = string.Empty;
CurrentUser = null;
IsLoggedIn = false;
}
private static void SetLoggedOut(string statusText)
{
CurrentUser = null;
IsLoggedIn = false;
StatusText = statusText;
NotifyStateChanged();
}
private static void SetBusy(bool isBusy, string? statusText = null)
{
IsBusy = isBusy;
if (statusText is not null)
StatusText = statusText;
NotifyStateChanged();
}
private static void NotifyStateChanged() => StateChanged?.Invoke(null, EventArgs.Empty);
}
using HaloPixelToolBox.Backend.Profiles.CacheProfiles;
using HaloPixelToolBox.Backend.Profiles.CrossVersionProfiles;
using HaloPixelToolBox.Core.Models.User;
using HaloPixelToolBox.Core.Utilities;
using System.Net;
using XFEExtension.NetCore.ServerInteractive.Models.RequesterModels;
namespace HaloPixelToolBox.Backend.Utilities;
/// <summary>
/// 统一维护管理端登录状态,并负责启动时恢复或重新创建管理员会话。
/// </summary>
public static class AdministratorSessionManager
{
private static readonly SemaphoreSlim s_authenticationLock = new(1, 1);
public static event EventHandler? StateChanged;
public static MyUserFaceInfo? CurrentUser { get; private set; }
public static bool IsLoggedIn { get; private set; }
public static bool IsBusy { get; private set; }
public static string StatusText { get; private set; } = "正在准备自动登录...";
public static string DisplayName => CurrentUser?.NickName ?? (IsLoggedIn ? CacheProfile.Account : "未登录");
/// <summary>
/// 优先恢复现有会话;会话失效时,使用本机保存的账号密码自动重新登录。
/// </summary>
public static async Task<bool> InitializeAsync(bool forceReconnect = false)
{
await s_authenticationLock.WaitAsync();
try
{
if (IsLoggedIn && !forceReconnect)
return true;
SetBusy(true, forceReconnect ? "正在重新连接服务器..." : "正在自动登录...");
if (!await ConnectAsync(forceReconnect))
{
SetLoggedOut("服务器连接失败,请在设置中检查服务器地址");
return false;
}
if (!string.IsNullOrWhiteSpace(CacheProfile.Session))
{
DataManager.ClientRequester.Session = CacheProfile.Session;
var restoredUser = await RestoreSessionCoreAsync();
if (restoredUser is not null)
{
CompleteLogin(restoredUser, CacheProfile.Session, "已自动恢复登录");
return true;
}
ClearSession();
StatusText = "登录会话已过期,正在使用保存的凭据重新登录...";
NotifyStateChanged();
}
if (string.IsNullOrWhiteSpace(CacheProfile.Account) || string.IsNullOrWhiteSpace(CacheProfile.Password))
{
SetLoggedOut("请输入管理员账号和密码,成功后将自动登录");
return false;
}
return await LoginCoreAsync(CacheProfile.Account, CacheProfile.Password, "已自动登录");
}
catch (Exception ex)
{
SetLoggedOut($"自动登录失败:{ex.Message}");
return false;
}
finally
{
SetBusy(false);
s_authenticationLock.Release();
}
}
/// <summary>
/// 使用用户输入的管理员凭据登录,并在成功后保存用于下次自动登录。
/// </summary>
public static async Task<bool> LoginAsync(string account, string password)
{
account = account.Trim();
if (string.IsNullOrWhiteSpace(account) || string.IsNullOrWhiteSpace(password))
{
SetLoggedOut("请输入管理员账号和密码");
return false;
}
await s_authenticationLock.WaitAsync();
try
{
SetBusy(true, "正在登录管理员账号...");
if (!await ConnectAsync(true))
{
SetLoggedOut("服务器连接失败,请在设置中检查服务器地址");
return false;
}
return await LoginCoreAsync(account, password, "已登录");
}
catch (Exception ex)
{
SetLoggedOut($"登录失败:{ex.Message}");
return false;
}
finally
{
SetBusy(false);
s_authenticationLock.Release();
}
}
/// <summary>
/// 退出管理端,并清除本机保存的密码,防止随后再次自动登录。
/// </summary>
public static async Task LogoutAsync()
{
await s_authenticationLock.WaitAsync();
try
{
ClearSession();
CacheProfile.Password = string.Empty;
SetLoggedOut("已退出登录;下次需要重新输入密码");
}
finally
{
s_authenticationLock.Release();
}
}
private static async Task<bool> ConnectAsync(bool forceReconnect)
{
var serverAddress = SystemProfile.ServerAddress.Trim();
if (!Uri.TryCreate(serverAddress, UriKind.Absolute, out var uri) ||
(uri.Scheme != Uri.UriSchemeHttp && uri.Scheme != Uri.UriSchemeHttps))
{
StatusText = "服务器地址无效,请输入完整的 HTTP 或 HTTPS 地址";
NotifyStateChanged();
return false;
}
return await DataManager.InitializeAsync([serverAddress], forceReconnect);
}
private static async Task<MyUserFaceInfo?> RestoreSessionCoreAsync()
{
var response = await DataManager.ClientRequester.Request<MyUserFaceInfo>("relogin");
return response.StatusCode == HttpStatusCode.OK && IsAdministrator(response.Result)
? response.Result
: null;
}
private static async Task<bool> LoginCoreAsync(string account, string password, string successMessage)
{
ClearSession();
var response = await DataManager.ClientRequester.Request<UserLoginResult<MyUserFaceInfo>>("login", account, password);
if (response.StatusCode != HttpStatusCode.OK || response.Result?.UserInfo is null)
{
SetLoggedOut("登录失败,请检查账号或密码");
return false;
}
if (!IsAdministrator(response.Result.UserInfo))
{
ClearSession();
SetLoggedOut("该账号没有管理员权限");
return false;
}
CacheProfile.Account = account;
CacheProfile.Password = password;
CompleteLogin(response.Result.UserInfo, response.Result.Session, successMessage);
return true;
}
private static bool IsAdministrator(MyUserFaceInfo? user) =>
user is not null && user.PermissionLevel >= (int)UserRole.管理员;
private static void CompleteLogin(MyUserFaceInfo user, string session, string successMessage)
{
DataManager.ClientRequester.Session = session;
CacheProfile.Session = session;
CurrentUser = user;
IsLoggedIn = true;
StatusText = $"{successMessage}:{user.NickName}({(UserRole)user.PermissionLevel})";
NotifyStateChanged();
}
private static void ClearSession()
{
DataManager.ClientRequester.Session = string.Empty;
CacheProfile.Session = string.Empty;
CurrentUser = null;
IsLoggedIn = false;
}
private static void SetLoggedOut(string statusText)
{
CurrentUser = null;
IsLoggedIn = false;
StatusText = statusText;
NotifyStateChanged();
}
private static void SetBusy(bool isBusy, string? statusText = null)
{
IsBusy = isBusy;
if (statusText is not null)
StatusText = statusText;
NotifyStateChanged();
}
private static void NotifyStateChanged() => StateChanged?.Invoke(null, EventArgs.Empty);
}