using Microsoft.AspNetCore.Components.Authorization; using Microsoft.JSInterop; using System.Net.Http.Headers; using System.Security.Claims; using System.Text.Json; using phronCare.UIBlazor.Extensions; namespace phronCare.UIBlazor.Services.Authorization { public class CustomAuthorizationProvider : AuthenticationStateProvider, ILoginService { private readonly IJSExtensions js; private readonly HttpClient httpClient; public static readonly string TOKENKEY = "phronCareTokenKey"; private AuthenticationState Anonimo => new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); public CustomAuthorizationProvider(IJSRuntime _js, HttpClient httpClient) { this.httpClient = httpClient; js = new IJSExtensions(_js); } public override async Task GetAuthenticationStateAsync() { var token = await js.GetFromLocalStorage(TOKENKEY); if (string.IsNullOrWhiteSpace(token) || !IsJwtFormat(token)) { await js.RemoveItem(TOKENKEY); return Anonimo; } return BuildAuthenticationState(token); } private AuthenticationState BuildAuthenticationState(string token) { httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt"))); } public async Task GetTokenData() { var authState = await GetAuthenticationStateAsync(); var user = authState.User; if (user.Identity is null || !user.Identity.IsAuthenticated) throw new InvalidOperationException("Usuario no autenticado."); var tokenString = await js.GetFromLocalStorage(TOKENKEY); // <-- ACA RECUPERAMOS EL JWT return new TokenData { userName = user.Identity.Name ?? string.Empty, role = user.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value ?? string.Empty, token = tokenString ?? string.Empty, // <-- ACA SETEAMOS el token string expiryTimeStamp = DateTime.UtcNow }; } //public async Task GetTokenData() //{ // var authState = await GetAuthenticationStateAsync(); // var user = authState.User; // if (user.Identity is null || !user.Identity.IsAuthenticated) // throw new InvalidOperationException("Usuario no autenticado."); // return new TokenData // { // userName = user.Identity.Name ?? string.Empty, // role = user.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role)?.Value ?? string.Empty, // expiryTimeStamp = DateTime.UtcNow // Opcional: ajustar si extraes exp claim // }; //} //public async Task Login(string token) //{ // await js.RemoveItem(TOKENKEY); // await js.SetInLocalStorage(TOKENKEY, token); // var authState = BuildAuthenticationState(token); // NotifyAuthenticationStateChanged(Task.FromResult(authState)); //} public async Task Login(string tokenJson) { var tokenData = JsonSerializer.Deserialize(tokenJson); if (tokenData is null || string.IsNullOrWhiteSpace(tokenData.token)) throw new Exception("Token inválido o mal formado."); await js.RemoveItem(TOKENKEY); await js.SetInLocalStorage(TOKENKEY, tokenData.token); // ✔️ Guardamos solo el JWT string var authState = BuildAuthenticationState(tokenData.token); NotifyAuthenticationStateChanged(Task.FromResult(authState)); } public async Task Logout() { httpClient.DefaultRequestHeaders.Authorization = null; await js.RemoveItem(TOKENKEY); NotifyAuthenticationStateChanged(Task.FromResult(Anonimo)); } private IEnumerable ParseClaimsFromJwt(string jwt) { var claims = new List(); var payload = jwt.Split('.')[1]; var jsonBytes = ParseBase64WithoutPadding(payload); var keyValuePairs = JsonSerializer.Deserialize>(jsonBytes); if (keyValuePairs != null && keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles)) { var rolesString = roles?.ToString() ?? string.Empty; if (!string.IsNullOrEmpty(rolesString)) { if (rolesString.Trim().StartsWith("[")) { var parsedRoles = JsonSerializer.Deserialize(rolesString) ?? Array.Empty(); foreach (var parsedRole in parsedRoles) { claims.Add(new Claim(ClaimTypes.Role, parsedRole)); } } else { claims.Add(new Claim(ClaimTypes.Role, rolesString)); } } keyValuePairs.Remove(ClaimTypes.Role); } if (keyValuePairs != null) { claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value?.ToString() ?? "defaultValue"))); } return claims; } private byte[] ParseBase64WithoutPadding(string base64) { switch (base64.Length % 4) { case 2: base64 += "=="; break; case 3: base64 += "="; break; } return Convert.FromBase64String(base64); } private bool IsJwtFormat(string token) { return token?.Count(c => c == '.') == 2; } public class TokenData { public string userName { get; set; } = string.Empty; public string role { get; set; } = string.Empty; public string token { get; set; } = string.Empty; public DateTime expiryTimeStamp { get; set; } } } }