This commit is contained in:
2025-12-04 12:12:46 +08:00
parent 5bdb04da15
commit ba1f54b21c
2 changed files with 10 additions and 68 deletions

View File

@@ -1,4 +1,5 @@
using Atomx.Admin.Client.Services;
using Atomx.Common.Constants;
using Atomx.Common.Models;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
@@ -24,9 +25,6 @@ namespace Atomx.Admin.Client.Utils
private readonly IHttpClientFactory _httpClientFactory;
private static readonly SemaphoreSlim _refreshLock = new(1, 1);
private const string AccessTokenKey = "accessToken";
private const string RefreshTokenKey = "refreshToken";
public AuthHeaderHandler(
ITokenProvider tokenProvider,
NavigationManager navigationManager,
@@ -71,7 +69,7 @@ namespace Atomx.Admin.Client.Utils
if (refreshed)
{
var newToken = await _localStorage.GetItemAsync<string>(AccessTokenKey);
var newToken = await _localStorage.GetItemAsync<string>(StorageKeys.AccessToken);
if (!string.IsNullOrEmpty(newToken))
{
var clonedRequest = await CloneHttpRequestMessageAsync(request, newToken);
@@ -109,8 +107,8 @@ namespace Atomx.Admin.Client.Utils
await _refreshLock.WaitAsync(cancellationToken);
try
{
var currentAccess = await _localStorage.GetItemAsync<string>(AccessTokenKey);
var currentRefresh = await _localStorage.GetItemAsync<string>(RefreshTokenKey);
var currentAccess = await _localStorage.GetItemAsync<string>(StorageKeys.AccessToken);
var currentRefresh = await _localStorage.GetItemAsync<string>(StorageKeys.RefreshToken);
if (string.IsNullOrEmpty(currentAccess) || string.IsNullOrEmpty(currentRefresh))
{
@@ -139,8 +137,8 @@ namespace Atomx.Admin.Client.Utils
{
_logger.LogWarning("Refresh request failed with status {Status}", resp.StatusCode);
// 如果刷新失败,移除本地 token防止无限重试
await _localStorage.RemoveItemAsync(AccessTokenKey);
await _localStorage.RemoveItemAsync(RefreshTokenKey);
await _localStorage.RemoveItemAsync(StorageKeys.AccessToken);
await _localStorage.RemoveItemAsync(StorageKeys.RefreshToken);
return false;
}
@@ -153,14 +151,14 @@ namespace Atomx.Admin.Client.Utils
if (authResp == null || string.IsNullOrEmpty(authResp.Token) || string.IsNullOrEmpty(authResp.RefreshToken))
{
_logger.LogWarning("Invalid response from refresh endpoint");
await _localStorage.RemoveItemAsync(AccessTokenKey);
await _localStorage.RemoveItemAsync(RefreshTokenKey);
await _localStorage.RemoveItemAsync(StorageKeys.AccessToken);
await _localStorage.RemoveItemAsync(StorageKeys.RefreshToken);
return false;
}
// 保存新的 tokens 到 localStorage
await _localStorage.SetItemAsync(AccessTokenKey, authResp.Token, cancellationToken);
await _localStorage.SetItemAsync(RefreshTokenKey, authResp.RefreshToken, cancellationToken);
await _localStorage.SetItemAsync(StorageKeys.AccessToken, authResp.Token, cancellationToken);
await _localStorage.SetItemAsync(StorageKeys.RefreshToken, authResp.RefreshToken, cancellationToken);
_logger.LogInformation("Token refreshed successfully");
return true;

View File

@@ -1,7 +1,6 @@
using Atomx.Admin.Client.Models;
using Atomx.Admin.Client.Validators;
using Atomx.Admin.Services;
using Atomx.Admin.Utils;
using Atomx.Common.Constants;
using Atomx.Common.Models;
using Atomx.Data;
@@ -137,33 +136,6 @@ namespace Atomx.Admin.Controllers
ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(_jwtSetting.AccessTokenExpirationMinutes)
});
// 另外将 tokens 写入 HttpOnly Cookie增强与传统中间件的兼容性
try
{
var cookieOptions = new CookieOptions
{
HttpOnly = true,
//Secure = !Request.IsLocal(), // 本地调试时允许 http
SameSite = SameSiteMode.Lax,
Expires = DateTimeOffset.UtcNow.AddMinutes(_jwtSetting.AccessTokenExpirationMinutes),
Path = "/"
};
Response.Cookies.Append("access_token", authResponse.Token, cookieOptions);
var refreshCookieOptions = new CookieOptions
{
HttpOnly = true,
//Secure = !Request.IsLocal(),
SameSite = SameSiteMode.Lax,
Expires = DateTimeOffset.UtcNow.AddMinutes(_jwtSetting.RefreshTokenExpirationMinutes),
Path = "/"
};
Response.Cookies.Append("refresh_token", authResponse.RefreshToken, refreshCookieOptions);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "设置 token cookie 失败(非致命)");
}
return new JsonResult(new ApiResult<AuthResponse>().IsSuccess(authResponse));
}
@@ -186,34 +158,6 @@ namespace Atomx.Admin.Controllers
var ip = _identityService.GetClientIp();
var newTokens = await _tokenService.RefreshTokenAsync(request.Token, request.RefreshToken, ip);
// 更新 cookie如存在
try
{
var cookieOptions = new CookieOptions
{
HttpOnly = true,
//Secure = !Request.IsLocal(),
SameSite = SameSiteMode.Lax,
Expires = DateTimeOffset.UtcNow.AddMinutes(_jwtSetting.AccessTokenExpirationMinutes),
Path = "/"
};
Response.Cookies.Append("access_token", newTokens.Token, cookieOptions);
var refreshCookieOptions = new CookieOptions
{
HttpOnly = true,
//Secure = !Request.IsLocal(),
SameSite = SameSiteMode.Lax,
Expires = DateTimeOffset.UtcNow.AddMinutes(_jwtSetting.RefreshTokenExpirationMinutes),
Path = "/"
};
Response.Cookies.Append("refresh_token", newTokens.RefreshToken, refreshCookieOptions);
}
catch (Exception ex)
{
_logger.LogDebug(ex, "刷新 token 时写 cookie 失败(允许)");
}
return new JsonResult(new ApiResult<AuthResponse>().IsSuccess(newTokens));
}
catch (SecurityTokenException ex)