This commit is contained in:
yxw
2025-12-04 19:07:04 +08:00
parent 6217a8ca55
commit bd95848972
13 changed files with 484 additions and 127 deletions

View File

@@ -1,11 +1,10 @@
using Blazored.LocalStorage;
using Atomx.Common.Configuration;
using Atomx.Common.Constants;
using Atomx.Utils.Extension;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Atomx.Common.Constants;
namespace Atomx.Admin.Client.Utils
{
@@ -13,59 +12,62 @@ namespace Atomx.Admin.Client.Utils
{
readonly ClaimsPrincipal anonymous = new(new ClaimsIdentity());
static readonly Task<AuthenticationState> defaultUnauthenticatedTask = Task.FromResult(new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity())));
readonly Task<AuthenticationState> authenticationStateTask = defaultUnauthenticatedTask;
// 如果运行在 Server 且在 prerender 时有 Persisted UserInfo则存储预设的 AuthenticationState
private Task<AuthenticationState>? _preRenderedAuthState;
readonly ILocalStorageService _localStorage;
public PersistentAuthenticationStateProvider(PersistentComponentState state, ILocalStorageService localStorageService)
public PersistentAuthenticationStateProvider(IServiceProvider serviceProvider, ILocalStorageService localStorageService)
{
_localStorage = localStorageService;
if (!state.TryTakeFromJson<UserInfo>(nameof(UserInfo), out var userInfo) || userInfo is null)
// 尝试有条件解析 PersistedComponentState仅在 Server 交互渲染时可用)
var state = serviceProvider.GetService<PersistentComponentState>();
if (state != null)
{
return;
}
var claims = new List<Claim>
if (state.TryTakeFromJson<UserInfo>(nameof(UserInfo), out var userInfo) && userInfo is not null)
{
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));
}
var claims = new List<Claim>
{
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 ?? Array.Empty<string>())
{
claims.Add(new Claim(ClaimKeys.Permission, role));
}
authenticationStateTask = Task.FromResult(
new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity(claims, authenticationType: nameof(PersistentAuthenticationStateProvider)))));
var cp = new ClaimsPrincipal(new ClaimsIdentity(claims, authenticationType: nameof(PersistentAuthenticationStateProvider)));
_preRenderedAuthState = Task.FromResult(new AuthenticationState(cp));
}
}
}
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
// 如果在 prerender 阶段已从 PersistentComponentState 恢复用户优先返回该状态Server prerender
if (_preRenderedAuthState != null)
return await _preRenderedAuthState;
try
{
var jwtToken = await _localStorage.GetItemAsStringAsync(StorageKeys.AccessToken);
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));
}
}
return new AuthenticationState(anonymous);
var getUserClaims = DecryptToken(jwtToken);
if (getUserClaims == null || string.IsNullOrEmpty(getUserClaims.Name))
return new AuthenticationState(anonymous);
var claimsPrincipal = SetClaimPrincipal(getUserClaims);
return new AuthenticationState(claimsPrincipal);
}
catch
{
return await Task.FromResult(new AuthenticationState(anonymous));
return new AuthenticationState(anonymous);
}
}
@@ -83,13 +85,12 @@ namespace Atomx.Admin.Client.Utils
new(ClaimKeys.Mobile, customUserClaims.MobilePhone),
new(ClaimKeys.Role, customUserClaims.Role.ToString()),
};
foreach (var role in customUserClaims.Permissions)
foreach (var role in customUserClaims.Permissions ?? Array.Empty<string>())
{
claims.Add(new Claim(ClaimKeys.Permission, role));
}
return new ClaimsPrincipal(new ClaimsIdentity(claims, authenticationType: nameof(PersistentAuthenticationStateProvider)));
}
}
public void UpdateAuthenticationState(string jwtToken = "")
@@ -113,8 +114,6 @@ namespace Atomx.Admin.Client.Utils
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;
@@ -132,7 +131,6 @@ namespace Atomx.Admin.Client.Utils
await _localStorage.RemoveItemAsync(StorageKeys.RefreshToken);
var authState = Task.FromResult(new AuthenticationState(anonymous));
NotifyAuthenticationStateChanged(authState);
}
}