using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Security.Claims; using System.Text.Json; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Authorization; namespace Client { public class JwtAuthStateProvider : AuthenticationStateProvider { private readonly AccountsClient _accounts; private readonly LocalStorage _storage; private readonly HttpClient _http; public JwtAuthStateProvider(AccountsClient accounts, LocalStorage storage, HttpClient http) { _accounts = accounts; _storage = storage; _http = http; } public override Task GetAuthenticationStateAsync() { return AuthenticationStateFromCurrentToken(); } public async Task TryLoginAsync(LoginViewModel cmd) { var token = await _accounts.LoginAsync(cmd); await _storage.Save("token", token); NotifyAuthenticationStateChanged(AuthenticationStateFromCurrentToken()); } public async Task Logout() { await _storage.Save("token", string.Empty); NotifyAuthenticationStateChanged(AuthenticationStateFromCurrentToken()); } private async Task AuthenticationStateFromCurrentToken() { var token = await _storage.Get("token"); if (string.IsNullOrWhiteSpace(token)) { _http.DefaultRequestHeaders.Authorization = null; return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())); } _http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); var claims = ParseClaimsFromJwt(token); var principal = new ClaimsPrincipal(new ClaimsIdentity(claims, "jwt", "unique_name", null)); return new AuthenticationState(principal); } private IEnumerable ParseClaimsFromJwt(string jwt) { var claims = new List(); var payload = jwt.Split('.')[1]; var jsonBytes = ParseBase64WithoutPadding(payload); var keyValuePairs = JsonSerializer.Deserialize>(jsonBytes); keyValuePairs.TryGetValue(ClaimTypes.Role, out object roles); if (roles != null) { if (roles.ToString().Trim().StartsWith("[")) { var parsedRoles = JsonSerializer.Deserialize(roles.ToString()); foreach (var parsedRole in parsedRoles) { claims.Add(new Claim(ClaimTypes.Role, parsedRole)); } } else { claims.Add(new Claim(ClaimTypes.Role, roles.ToString())); } keyValuePairs.Remove(ClaimTypes.Role); } claims.AddRange(keyValuePairs.Select(kvp => new Claim(kvp.Key, kvp.Value.ToString()))); return claims; } private byte[] ParseBase64WithoutPadding(string base64) { switch (base64.Length % 4) { case 2: base64 += "=="; break; case 3: base64 += "="; break; } return Convert.FromBase64String(base64); } } }