using Blazored.LocalStorage; using Atomx.Common.Configuration; using Atomx.Common.Utils; using Atomx.Utils.Extension; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Authorization; using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; namespace Atomx.Admin.Client.Utils { public class PersistentAuthenticationStateProvider : AuthenticationStateProvider { readonly ClaimsPrincipal anonymous = new(new ClaimsIdentity()); static readonly Task defaultUnauthenticatedTask = Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()))); readonly Task authenticationStateTask = defaultUnauthenticatedTask; readonly ILocalStorageService _localStorage; public PersistentAuthenticationStateProvider(PersistentComponentState state, ILocalStorageService localStorageService) { _localStorage = localStorageService; if (!state.TryTakeFromJson(nameof(UserInfo), out var userInfo) || userInfo is null) { return; } var claims = new List { new(ClaimKeys.Id, userInfo.Id.ToString()), new(ClaimKeys.Name, userInfo.Name), new(ClaimKeys.Email, userInfo.Email), new(ClaimKeys.Mobile, userInfo.MobilePhone), new(ClaimKeys.Role, userInfo.Role), }; foreach (var role in userInfo.Permissions) { claims.Add(new Claim(ClaimKeys.Permission, role)); } authenticationStateTask = Task.FromResult( new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims, authenticationType: nameof(PersistentAuthenticationStateProvider))))); } public override async Task GetAuthenticationStateAsync() { try { var jwtToken = await _localStorage.GetItemAsStringAsync(StorageKeys.JWTTokenKeyName); if (string.IsNullOrEmpty(jwtToken)) return await Task.FromResult(new AuthenticationState(anonymous)); else { var getUserClaims = DecryptToken(jwtToken); if (getUserClaims == null) return await Task.FromResult(new AuthenticationState(anonymous)); else { var claimsPrincipal = SetClaimPrincipal(getUserClaims); return await Task.FromResult(new AuthenticationState(claimsPrincipal)); } } } catch { return await Task.FromResult(new AuthenticationState(anonymous)); } } public ClaimsPrincipal SetClaimPrincipal(UserInfo customUserClaims) { if (string.IsNullOrEmpty(customUserClaims.Name)) return new ClaimsPrincipal(); else { var claims = new List { new(ClaimKeys.Id, customUserClaims.Id.ToString()), new(ClaimKeys.Name, customUserClaims.Name), new(ClaimKeys.Email, customUserClaims.Email), new(ClaimKeys.Mobile, customUserClaims.MobilePhone), new(ClaimKeys.Role, customUserClaims.Role.ToString()), }; foreach (var role in customUserClaims.Permissions) { claims.Add(new Claim(ClaimKeys.Permission, role)); } return new ClaimsPrincipal(new ClaimsIdentity(claims, authenticationType: nameof(PersistentAuthenticationStateProvider))); } } public void UpdateAuthenticationState(string jwtToken = "") { var claimsPrincipal = new ClaimsPrincipal(); if (!string.IsNullOrEmpty(jwtToken)) { var getUserClaims = DecryptToken(jwtToken); claimsPrincipal = SetClaimPrincipal(getUserClaims); } NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(claimsPrincipal))); } private UserInfo DecryptToken(string jwtToken) { if (string.IsNullOrEmpty(jwtToken)) return new UserInfo(); else { var handler = new JwtSecurityTokenHandler(); var token = handler.ReadJwtToken(jwtToken); var id = token.Claims.SingleOrDefault(x => x.Type == ClaimKeys.Id)?.Value ?? string.Empty; var name = token.Claims.SingleOrDefault(x => x.Type == ClaimKeys.Name)?.Value ?? string.Empty; var email = token.Claims.SingleOrDefault(x => x.Type == ClaimKeys.Email)?.Value ?? string.Empty; var phone = token.Claims.SingleOrDefault(x => x.Type == ClaimKeys.Mobile)?.Value ?? string.Empty; var role = token.Claims.SingleOrDefault(x => x.Type == ClaimKeys.Role)?.Value ?? string.Empty; var permissions = token.Claims.Where(x => x.Type == ClaimKeys.Permission).Select(s => s.Value).ToArray(); return new UserInfo(id.ToLong(), name, email, phone, role, permissions); } } public async Task MarkUserAsLoggedOut() { await _localStorage.RemoveItemAsync(StorageKeys.JWTTokenKeyName); await _localStorage.RemoveItemAsync(StorageKeys.RefreshTokenKeyName); var authState = Task.FromResult(new AuthenticationState(anonymous)); NotifyAuthenticationStateChanged(authState); } } public record UserInfo(long Id = 0, string Name = null!, string Email = null!, string MobilePhone = null!, string Role = null!, string[] Permissions = null!); }