using System.Security.Claims; using Microsoft.AspNetCore.Components.Authorization; using QuantEngine.Web.Client.Services; namespace QuantEngine.Web.Client.Infrastructure { public class CustomAuthenticationStateProvider : AuthenticationStateProvider { private readonly LocalStorageService _localStorage; private readonly HttpClient _http; private readonly ClaimsPrincipal _anonymous = new ClaimsPrincipal(new ClaimsIdentity()); private const string TokenKey = "quant_admin_access_token"; private const string UsernameKey = "quant_admin_username"; private const string RoleKey = "quant_admin_role"; private const string RememberUsernameKey = "quant_admin_remember_username"; public CustomAuthenticationStateProvider(LocalStorageService localStorage, HttpClient http) { _localStorage = localStorage; _http = http; } public override async Task GetAuthenticationStateAsync() { try { var token = await _localStorage.GetAsync(TokenKey); var username = await _localStorage.GetAsync(UsernameKey); var role = await _localStorage.GetAsync(RoleKey) ?? "Admin"; if (!string.IsNullOrWhiteSpace(token) && !string.IsNullOrWhiteSpace(username)) { var request = new HttpRequestMessage(HttpMethod.Get, "api/auth/me"); request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); var response = await _http.SendAsync(request); if (!response.IsSuccessStatusCode) { await MarkUserAsLoggedOutAsync(); return new AuthenticationState(_anonymous); } var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username), new Claim(ClaimTypes.Role, role) }, "QuantAdminAuth"); var user = new ClaimsPrincipal(identity); return new AuthenticationState(user); } } catch { // Return anonymous if localStorage isn't ready } return new AuthenticationState(_anonymous); } public async Task MarkUserAsAuthenticatedAsync(string username, string accessToken, string role) { await MarkUserAsAuthenticatedAsync(username, accessToken, role, rememberUsername: true); } public async Task MarkUserAsAuthenticatedAsync(string username, string accessToken, string role, bool rememberUsername) { await _localStorage.SetAsync(TokenKey, accessToken); if (rememberUsername) { await _localStorage.SetAsync(UsernameKey, username); await _localStorage.SetAsync(RememberUsernameKey, true); } else { await _localStorage.DeleteAsync(UsernameKey); await _localStorage.SetAsync(RememberUsernameKey, false); } await _localStorage.SetAsync(RoleKey, role); var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username), new Claim(ClaimTypes.Role, role) }, "QuantAdminAuth"); var user = new ClaimsPrincipal(identity); NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user))); } public async Task MarkUserAsLoggedOutAsync() { await _localStorage.DeleteAsync(TokenKey); await _localStorage.DeleteAsync(RoleKey); var rememberUsername = await _localStorage.GetAsync(RememberUsernameKey); if (!rememberUsername) { await _localStorage.DeleteAsync(UsernameKey); } NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(_anonymous))); } public async Task LogoutFromServerAsync() { var token = await _localStorage.GetAsync(TokenKey); if (!string.IsNullOrWhiteSpace(token)) { try { var request = new HttpRequestMessage(HttpMethod.Post, "api/auth/logout"); request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token); await _http.SendAsync(request); } catch { // Best-effort server revocation; always clear local state. } } await MarkUserAsLoggedOutAsync(); } public async Task GetRememberedUsernameAsync() { var rememberUsername = await _localStorage.GetAsync(RememberUsernameKey); if (!rememberUsername) { return null; } return await _localStorage.GetAsync(UsernameKey); } } }