using System; using System.Text.Json; namespace Elfisa.Core; /// Текущая сессия пользователя (токен, роль, логин). Сохраняется между запусками. public sealed class Session { public static Session Current { get; } = new(); public string? Token { get; set; } public string? Role { get; set; } public string? Username { get; set; } public bool IsAuthenticated => !string.IsNullOrWhiteSpace(Token); /// Сохранить сессию в настройки (чтобы не логиниться каждый раз). public void Save() { SettingsStore.Current.Token = Token; SettingsStore.Current.Role = Role; SettingsStore.Current.Username = Username; SettingsStore.Save(); } /// Восстановить сессию из настроек, если токен есть и не истёк. public static bool TryRestore() { var s = SettingsStore.Current; if (string.IsNullOrWhiteSpace(s.Token) || IsJwtExpired(s.Token)) return false; Current.Token = s.Token; Current.Role = s.Role; Current.Username = s.Username; return true; } public void Clear() { Token = null; Role = null; Username = null; SettingsStore.Current.Token = null; SettingsStore.Current.Role = null; SettingsStore.Current.Username = null; SettingsStore.Save(); } /// Проверяет, истёк ли JWT (по claim exp), с запасом в 1 минуту. private static bool IsJwtExpired(string token) { try { var parts = token.Split('.'); if (parts.Length != 3) return true; var payload = parts[1].Replace('-', '+').Replace('_', '/'); switch (payload.Length % 4) { case 2: payload += "=="; break; case 3: payload += "="; break; } var json = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(payload)); using var doc = JsonDocument.Parse(json); if (doc.RootElement.TryGetProperty("exp", out var exp) && exp.TryGetInt64(out var expUnix)) return DateTimeOffset.UtcNow.ToUnixTimeSeconds() >= expUnix - 60; return false; // нет exp — считаем валидным } catch { return true; } } }