😎优化代码

This commit is contained in:
zuohuaijun 2025-08-28 01:54:44 +08:00
parent d1021dde55
commit 7f4aee2465
6 changed files with 78 additions and 67 deletions

View File

@ -7,13 +7,12 @@
namespace Admin.NET.Core;
/// <summary>
/// 自定义Json转换字段名
/// 自定义JSON属性特性仅在三方接口序列化时生效
/// </summary>
[AttributeUsage(AttributeTargets.Property)]
public class CustomJsonPropertyAttribute(string name) : Attribute
{
/// <summary>
/// 序列化名称
/// </summary>
public string Name { get; } = name;
public string DateFormat { get; set; } = "yyyy-MM-dd HH:mm:ss";
}

View File

@ -27,7 +27,7 @@ public partial class SysLogHttp : EntityTenantId
/// <summary>
/// 接口描述
/// </summary>
[SugarColumn(ColumnDescription = "接口描述", Length = 32)]
[SugarColumn(ColumnDescription = "接口描述", Length = 64)]
[MaxLength(32)]
public string? HttpApiDesc { get; set; }
@ -47,7 +47,8 @@ public partial class SysLogHttp : EntityTenantId
/// <summary>
/// 模块名称
/// </summary>
[SugarColumn(ColumnDescription = "模块名称")]
[SugarColumn(ColumnDescription = "模块名称", Length = 64)]
[MaxLength(32)]
public string? ActionName { get; set; }
/// <summary>
@ -68,6 +69,12 @@ public partial class SysLogHttp : EntityTenantId
[SugarColumn(ColumnDescription = "请求体", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public string? RequestBody { get; set; }
/// <summary>
/// 请求体明文
/// </summary>
[SugarColumn(ColumnDescription = "请求体明文", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public string? RequestBodyPlaintext { get; set; }
/// <summary>
/// 响应状态码
/// </summary>
@ -86,6 +93,12 @@ public partial class SysLogHttp : EntityTenantId
[SugarColumn(ColumnDescription = "响应体", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public string? ResponseBody { get; set; }
/// <summary>
/// 响应体明文
/// </summary>
[SugarColumn(ColumnDescription = "响应体明文", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public string? ResponseBodyPlaintext { get; set; }
/// <summary>
/// 异常信息
/// </summary>

View File

@ -9,8 +9,7 @@ namespace Admin.NET.Core;
/// <summary>
/// Http远程服务扩展
/// </summary>
public static class HttpRemotesExtension
{
public static class HttpRemotesExtension {
/// <summary>
/// 添加Http远程服务
/// </summary>
@ -18,7 +17,7 @@ public static class HttpRemotesExtension
/// <returns></returns>
public static IServiceCollection AddHttpRemoteClientService(this IServiceCollection services)
{
var options = App.GetConfig<object>("HttpRemotes") ?? throw new Exception("未正确配置HttpRemotes.json");
var options = App.GetOptions<HttpRemotesOptions>() ?? throw new Exception("未正确配置HttpRemotes.json");
foreach (var prop in options.GetType().GetProperties())
{
if (prop.GetValue(options) is not HttpRemoteItem opt) continue;
@ -28,11 +27,10 @@ public static class HttpRemotesExtension
client.Timeout = TimeSpan.FromSeconds(opt.Timeout);
foreach (var kv in opt.Headers) client.DefaultRequestHeaders.Add(kv.Key, kv.Value);
})
.AddHttpMessageHandler<HttpLoggingHandler>()
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
{
.ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler {
UseCookies = opt.UseCookies
});
})
.AddHttpMessageHandler<HttpLoggingHandler>();
}
return services;
}
@ -41,52 +39,11 @@ public static class HttpRemotesExtension
/// 携带接口描述相关属性
/// </summary>
/// <param name="builder"></param>
/// <param name="httpName"></param>
/// <param name="attr"></param>
/// <param name="reqPlaintext"></param>
/// <returns></returns>
public static HttpRequestBuilder SetRemoteApiAttr(this HttpRequestBuilder builder, string httpName, HttpRemoteApiAttribute attr)
public static HttpRequestBuilder SetRemoteApiAttr(this HttpRequestBuilder builder, HttpRemoteApiAttribute attr, string reqPlaintext = null)
{
return HttpLoggingHandler.SetRemoteApiAttr(builder, httpName, attr);
return HttpLoggingHandler.SetRemoteApiAttr(builder, attr, reqPlaintext);
}
}
/// <summary>
/// 远程请求配置项
/// </summary>
public sealed class HttpRemoteItem
{
/// <summary>
/// 是否启用日志
/// </summary>
public bool EnabledLog { get; set; }
/// <summary>
/// 是否启用代理
/// </summary>
public bool EnabledProxy { get; set; }
/// <summary>
/// 服务名称
/// </summary>
public string HttpName { get; set; }
/// <summary>
/// 服务地址
/// </summary>
public string BaseAddress { get; set; }
/// <summary>
/// 请求超时时间
/// </summary>
public int Timeout { get; set; }
/// <summary>
/// 是否自动处理Cookie
/// </summary>
public bool UseCookies { get; set; }
/// <summary>
/// 请求头
/// </summary>
public Dictionary<string, string> Headers { get; set; }
}

View File

@ -8,11 +8,14 @@ using System.Net.Http.Headers;
namespace Admin.NET.Core;
/// <summary>
/// http日志处理
/// </summary>
public class HttpLoggingHandler : DelegatingHandler, ITransient
{
private static readonly string RespPlaintextKey = CommonConst.HttpRemoteHeaderKeyPrefix + "RESP_PLAINTEXT__";
private static readonly string ReqPlaintextKey = CommonConst.HttpRemoteHeaderKeyPrefix + "REQ_PLAINTEXT__";
private static readonly string IgnoreLogKey = CommonConst.HttpRemoteHeaderKeyPrefix + "IGNORE_LOG__";
private static readonly string ApiDescKey = CommonConst.HttpRemoteHeaderKeyPrefix + "API_DESC__";
private static readonly string HttpNameKey = CommonConst.HttpRemoteHeaderKeyPrefix + "NAME__";
@ -27,10 +30,10 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
_eventPublisher = eventPublisher;
_sysConfigService = sysConfigService;
var options = App.GetConfig<object>("HttpRemotes") ?? throw new Exception("未正确配置HttpRemotes.json");
var options = App.GetOptions<HttpRemotesOptions>() ?? throw new Exception("[HttpRemote] 未正确配置HttpRemotes.json");
_enabledLogMap = options.GetType().GetProperties()
.Where(u => u.PropertyType == typeof(HttpRemoteItem))
.ToDictionary(u => u.GetValue(options) is HttpRemoteItem opt ? opt.HttpName : "",
.ToDictionary(u => u.GetValue(options) is HttpRemoteItem opt ? opt.HttpName : throw new Exception("[HttpRemote] 未正确配置HttpName"),
u => u.GetValue(options) is HttpRemoteItem { EnabledLog: true });
}
@ -42,7 +45,7 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
if (!enabledLog) return await base.SendAsync(request, cancellationToken);
// 判断当前配置日志开关
(string apiDesc, bool ignoreLog) = GetRemoteApiAttrAndRemove(request.Headers);
(string apiDesc, bool ignoreLog, string reqPlaintext) = GetRemoteApiAttrAndRemove(request.Headers);
_ = request.Options.TryGetValue<string>(HttpNameKey, out var httpName);
if (!string.IsNullOrWhiteSpace(httpName)) enabledLog = _enabledLogMap.GetOrDefault(httpName);
if (!enabledLog || ignoreLog) return await base.SendAsync(request, cancellationToken);
@ -57,6 +60,7 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
ActionName = urlList.Length >= 2 ? $"{urlList[^2]}/{urlList[^1]}" : urlList.Length >= 1 ? urlList[^1] : null,
RequestUrl = request.RequestUri?.ToString(),
RequestHeaders = request.Headers.ToDictionary(u => u.Key, u => u.Value.Join(";")).ToJson(),
RequestBodyPlaintext = reqPlaintext,
TenantId = _userManager.Value?.TenantId,
CreateUserId = _userManager.Value?.UserId,
CreateUserName = _userManager.Value?.RealName,
@ -96,15 +100,16 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
/// </summary>
/// <param name="headers"></param>
/// <returns></returns>
private static (string apiDesc, bool ignoreLog) GetRemoteApiAttrAndRemove(HttpRequestHeaders headers)
private static (string apiDesc, bool ignoreLog, string reqPlaintext) GetRemoteApiAttrAndRemove(HttpRequestHeaders headers)
{
var result = new
{
ReqPlaintext = headers?.FirstOrDefault(u => u.Key == ReqPlaintextKey).Value?.FirstOrDefault()?.ToString(),
ApiDesc = headers?.FirstOrDefault(u => u.Key == ApiDescKey).Value?.FirstOrDefault()?.ToString(),
IgnoreLog = headers?.FirstOrDefault(u => u.Key == IgnoreLogKey).Value?.ToBoolean() ?? false,
};
RemoveRemoteApiAttr(headers);
return (result.ApiDesc, result.IgnoreLog);
return (result.ApiDesc, result.IgnoreLog, result.ReqPlaintext);
}
/// <summary>
@ -126,14 +131,14 @@ public class HttpLoggingHandler : DelegatingHandler, ITransient
/// 设置接口描述相关属性
/// </summary>
/// <param name="builder"></param>
/// <param name="httpName"></param>
/// <param name="attr"></param>
/// <param name="reqPlaintext">请求文明</param>
/// <returns></returns>
public static HttpRequestBuilder SetRemoteApiAttr(HttpRequestBuilder builder, string httpName, HttpRemoteApiAttribute attr)
public static HttpRequestBuilder SetRemoteApiAttr(HttpRequestBuilder builder, HttpRemoteApiAttribute attr, string reqPlaintext = null)
{
builder.WithHeader(IgnoreLogKey, attr.IgnoreLog, replace: true);
builder.WithHeader(ApiDescKey, attr.Desc, replace: true);
builder.SetHttpClientName(httpName);
builder.WithHeader(ReqPlaintextKey, reqPlaintext, replace:true);
builder.WithHeader(IgnoreLogKey, attr.IgnoreLog, replace:true);
builder.WithHeader(ApiDescKey, attr.Desc, replace:true);
return builder;
}
}

View File

@ -56,6 +56,11 @@ public class PageLogHttpOutput
/// </summary>
public string RequestBody { get; set; }
/// <summary>
/// 请求体(明文)
/// </summary>
public string RequestBodyPlaintext { get; set; }
/// <summary>
/// 响应状态码
/// </summary>
@ -71,6 +76,11 @@ public class PageLogHttpOutput
/// </summary>
public string ResponseBody { get; set; }
/// <summary>
/// 响应体(明文)
/// </summary>
public string ResponseBodyPlaintext { get; set; }
/// <summary>
/// 异常信息
/// </summary>
@ -100,6 +110,7 @@ public class PageLogHttpOutput
/// 创建用户
/// </summary>
public string CreateUserName { get; set; }
}
/// <summary>

View File

@ -4,6 +4,7 @@
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Microsoft.AspNetCore.WebUtilities;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Utilities.Encoders;
@ -35,6 +36,31 @@ public class CryptogramHelper
};
}
/// <summary>
/// 根据字符串生成SM4密钥
/// </summary>
public static string GetSm4Key(string identity)
{
ArgumentException.ThrowIfNullOrWhiteSpace(identity, nameof(identity));
try
{
byte[] decoded = WebEncoders.Base64UrlDecode(identity);
if (decoded.Length < 16)
throw new ArgumentException($"Base64 解码后数据长度不足 16 字节,实际长度: {decoded.Length}", nameof(identity));
byte[] keyCode = new byte[16];
Buffer.BlockCopy(decoded, 0, keyCode, 0, 16);
return Hex.ToHexString(keyCode);
}
catch (FormatException ex)
{
throw new ArgumentException("无效的 Base64Url 编码格式", nameof(identity), ex);
}
}
/// <summary>
/// 加密
/// </summary>