fix authorize

This commit is contained in:
2025-12-05 00:27:43 +08:00
parent bd95848972
commit 00dd4fa958
18 changed files with 300 additions and 168 deletions

View File

@@ -1,8 +1,11 @@
using Atomx.Common.Models;
using Atomx.Utils.Json;
using System.Net.Http.Json;
using System.Text;
using Microsoft.AspNetCore.Http;
using System.Net;
using System.Net.Http.Json;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
namespace Atomx.Admin.Client.Services
{
@@ -10,11 +13,13 @@ namespace Atomx.Admin.Client.Services
{
private readonly HttpClient _httpClient;
private readonly IHttpContextAccessor? _httpContextAccessor;
private readonly ILogger<HttpService> _logger;
public HttpService(HttpClient httpClient, IHttpContextAccessor? httpContextAccessor = null)
public HttpService(HttpClient httpClient, IHttpContextAccessor? httpContextAccessor = null, ILogger<HttpService>? logger = null)
{
_httpClient = httpClient;
_httpContextAccessor = httpContextAccessor;
_logger = logger ?? Microsoft.Extensions.Logging.Abstractions.NullLogger<HttpService>.Instance;
}
public async Task<T> Get<T>(string url)
@@ -29,6 +34,8 @@ namespace Atomx.Admin.Client.Services
}
else
{
await LogNonSuccessAsync(url, response);
ThrowForStatus(response.StatusCode, url);
throw new Exception($"Error: {response.StatusCode}");
}
}
@@ -50,6 +57,8 @@ namespace Atomx.Admin.Client.Services
}
else
{
await LogNonSuccessAsync(url, response);
ThrowForStatus(response.StatusCode, url);
throw new Exception($"Error: {response.StatusCode}");
}
}
@@ -78,13 +87,16 @@ namespace Atomx.Admin.Client.Services
}
else
{
// 明确抛 Unauthorized 以便上层按需处理
throw new Exception($"Error: {response.StatusCode}");
await LogNonSuccessAsync(url, response);
// 明确在 401/403 场景抛出授权异常以便上层 UI/组件做特殊处理
ThrowForStatus(response.StatusCode, url);
throw new Exception($"Error: {response.StatusCode}");
}
}
catch (HttpRequestException ex)
{
Console.WriteLine(ex.ToString());
_logger.LogError(ex, "HttpRequestException while calling {Url}", url);
Console.Error.WriteLine($"[{DateTime.UtcNow:o}] HttpRequestException Url:{url} Error:{ex.Message}");
throw new Exception($"api {url} service failure");
}
}
@@ -115,5 +127,64 @@ namespace Atomx.Admin.Client.Services
// 忽略任何转发异常,保持健壮性
}
}
private async Task LogNonSuccessAsync(string url, HttpResponseMessage response)
{
try
{
var status = response.StatusCode;
var reason = response.ReasonPhrase;
string userId = "unknown";
string ip = "unknown";
var ctx = _httpContextAccessor?.HttpContext;
if (ctx != null)
{
userId = ctx.User?.FindFirst(ClaimTypes.NameIdentifier)?.Value
?? ctx.User?.FindFirst("sub")?.Value
?? "unknown";
if (ctx.Request.Headers.TryGetValue("X-Forwarded-For", out var xff) && !string.IsNullOrWhiteSpace(xff))
{
ip = xff.ToString().Split(',')[0].Trim();
}
else
{
ip = ctx.Connection.RemoteIpAddress?.ToString() ?? "unknown";
}
}
// 结构化日志记录
_logger.LogWarning("UserId:{UserId} Url:{Url} Ip:{Ip} HttpStatus:{StatusCode} Reason:{ReasonPhrase}", userId, url, ip, (int)status, reason);
// 控制台输出一份,便于本地/容器查看
var consoleMsg = new
{
Timestamp = DateTime.UtcNow.ToString("o"),
Level = "Warning",
UserId = userId,
Url = url,
Ip = ip,
Status = (int)status,
Reason = reason
};
Console.WriteLine(JsonSerializer.Serialize(consoleMsg));
}
catch (Exception ex)
{
// 日志失败不能影响主流程
_logger.LogError(ex, "Failed to log non-success response for {Url}", url);
}
}
private void ThrowForStatus(HttpStatusCode statusCode, string url)
{
if (statusCode == HttpStatusCode.Unauthorized || statusCode == HttpStatusCode.Forbidden)
{
// 抛出明确的授权异常,便于上层按需处理(例如提示登陆、重定向或显示权限不足)
throw new UnauthorizedAccessException($"Error: {statusCode} when calling {url}");
}
}
}
}