using OASystem.Domain.AesEncryption;
using OASystem.Domain.Attributes;
using OASystem.Domain.Entities.Customer;
using Org.BouncyCastle.Asn1.Pkcs;
using System.Net;
using UAParser;
using static OASystem.API.OAMethodLib.JWTHelper;
namespace OASystem.API.Middlewares
{
///
/// 指定API操作记录信息
///
public class RecordAPIOperationMiddleware
{
private readonly RequestDelegate _next;
private readonly HttpClient _httpClient;
private readonly IConfiguration _config;
private readonly SqlSugarClient _sqlSugar;
///
/// 初始化
///
///
///
///
///
public RecordAPIOperationMiddleware(RequestDelegate next, IConfiguration config, HttpClient httpClient, SqlSugarClient sqlSugar)
{
_next = next;
_httpClient = httpClient;
_config = config;
_sqlSugar = sqlSugar;
}
public async Task InvokeAsync(HttpContext context)
{
// 启用请求体流的缓冲,允许多次读取
context.Request.EnableBuffering();
// 读取请求体内容
var requestBodyText = await ReadRequestBody(context.Request);
// 检查控制器方法是否使用了自定义属性
var endpoint = context.GetEndpoint();
var apiLogAttribute = endpoint?.Metadata?.GetMetadata();
if (apiLogAttribute != null)
{
var startTime = DateTime.UtcNow;
int portType = 1, userId = 0, id = 0, status = 0;
string updatePreData = string.Empty, updateBefData = string.Empty;
bool param5Bool = false, param6Bool = false;
try
{
userId = await ReadToken(context);
if (!string.IsNullOrEmpty(requestBodyText))
{
object param1 = string.Empty, param2 = string.Empty, param3 = string.Empty, param4 = string.Empty,
param5 = string.Empty, param6 = string.Empty, param7 = string.Empty, param8 = string.Empty;
var requestBodyJson = JsonConvert.DeserializeObject>(requestBodyText);
bool exists1 = requestBodyJson.TryGetValue("portType", out param1);
bool exists2 = requestBodyJson.TryGetValue("userId", out param2);
bool exists3 = requestBodyJson.TryGetValue("currUserId", out param3);
bool exists4 = requestBodyJson.TryGetValue("createUserId", out param4);
bool exists5 = requestBodyJson.TryGetValue("id", out param5);
bool exists6 = requestBodyJson.TryGetValue("status", out param6);
bool exists7 = requestBodyJson.TryGetValue("operationUserId", out param7);
bool exists8 = requestBodyJson.TryGetValue("deleteUserId", out param8);
if (exists1) int.TryParse(param1.ToString(), out portType);
//用户Id处理
if (userId < 1)
{
if (apiLogAttribute.OperationEnum == OperationEnum.Login)
{
var number = requestBodyJson?["number"].ToString();
if (!string.IsNullOrEmpty(number))
{
var info = await _sqlSugar.Queryable().Where(x => x.IsDel == 0 && x.Number.Equals(number)).FirstAsync();
userId = info.Id;
}
}
else
{
if (exists2) int.TryParse(param2.ToString(), out userId);
else if (exists3) int.TryParse(param3.ToString(), out userId);
else if (exists4) int.TryParse(param4.ToString(), out userId);
else if (exists7) int.TryParse(param7.ToString(), out userId);
else if (exists8) int.TryParse(param8.ToString(), out userId);
}
}
//编辑前数据查询;
if (exists5) param5Bool = int.TryParse(param5.ToString(), out id);
if (exists6) param6Bool = int.TryParse(param6.ToString(), out status);
if (param6Bool)
{
// 2 修改
if (status == 1) apiLogAttribute.OperationEnum = OperationEnum.Add;
else if (status == 2)
{
apiLogAttribute.OperationEnum = OperationEnum.Edit;
updatePreData = await TableInfoToJson(apiLogAttribute.TableName, id);
}
}
else if (param5Bool)
{
if (apiLogAttribute.OperationEnum != OperationEnum.Del)
{
// id > 0 修改
if (id < 1) apiLogAttribute.OperationEnum = OperationEnum.Add;
else if (id > 0)
{
apiLogAttribute.OperationEnum = OperationEnum.Edit;
updatePreData = await TableInfoToJson(apiLogAttribute.TableName, id);
}
}
}
}
}
catch (JsonException) { }
// 保存原始响应体流
var originalResponseBody = context.Response.Body;
// 创建一个新的内存流来捕获响应体
using var responseMemoryStream = new MemoryStream();
context.Response.Body = responseMemoryStream;
// 调用下一个中间件
await _next(context);
// 重置响应体流的位置
responseMemoryStream.Position = 0;
// 读取响应体内容
var responseBodyText = await ReadResponseBody(responseMemoryStream);
// 将响应体内容写回原始响应体流
await responseMemoryStream.CopyToAsync(originalResponseBody);
//修改后数据查询
if (param6Bool)
{
// 2 修改
if (status == 2) updateBefData = await TableInfoToJson(apiLogAttribute.TableName, id);
}
else if (param5Bool)
{
if (apiLogAttribute.OperationEnum != OperationEnum.Del)
{
// id > 0 修改
if (id > 0) updateBefData = await TableInfoToJson(apiLogAttribute.TableName, id);
}
}
string remoteIp = string.Empty,
location = string.Empty;
// 检查请求头中的X-Forwarded-For,以获取真实的客户端IP地址
if (context.Request.Headers.ContainsKey("X-Forwarded-For"))
{
remoteIp = context.Request.Headers["X-Forwarded-For"].ToString().Split(',', StringSplitOptions.RemoveEmptyEntries)[0];
//_logger.LogInformation($"IP:{remoteIp}");
}
else
{
remoteIp = context.Connection.RemoteIpAddress?.ToString();
}
(remoteIp, location) = await GetIpInfo(remoteIp);
//remoteIp = await GetExternalIp();
//location = await GetIpLocation(remoteIp);
string deviceType = string.Empty, browser = string.Empty, os = string.Empty;
var userAgent = context.Request.Headers["User-Agent"].FirstOrDefault();
if (!string.IsNullOrEmpty(userAgent))
{
// 解析User-Agent头
var parser = Parser.GetDefault();
var client = parser.Parse(userAgent);
// 提取浏览器信息
browser = client.UA.Family; // 浏览器名称
var browserVersion = client.UA.Major + "." + client.UA.Minor + "." + client.UA.Patch; // 浏览器版本
browser += $"({browserVersion})";
// 提取操作系统信息
os = client.OS.Family; // 操作系统名称
var osVersion = string.Empty; // 操作系统版本
if (!string.IsNullOrEmpty(client.OS.Major)) osVersion += client.OS.Major;
if (!string.IsNullOrEmpty(client.OS.Minor)) osVersion += "." + client.OS.Minor;
if (!string.IsNullOrEmpty(client.OS.Patch)) osVersion += "." + client.OS.Patch;
if (!string.IsNullOrEmpty(osVersion)) os += $"({osVersion})";
// 提取设备信息
deviceType = client.Device.Family; // 设备类型,如 'mobile', 'tablet', 'desktop' 等
}
// 记录请求结束时间
var endTime = DateTime.UtcNow;
// 计算耗时
var duration = (long)(endTime - startTime).TotalMilliseconds;
var logInfo = new Crm_TableOperationRecord()
{
TableName = apiLogAttribute.TableName,
PortType = portType,
OperationItem = apiLogAttribute.OperationEnum,
DataId = id,
RequestUrl = context.Request.Path,
RemoteIp = remoteIp,
Location = location,
RequestParam = !string.IsNullOrEmpty(requestBodyText) ? JsonConvert.SerializeObject(requestBodyText) : null,
ReturnResult = !string.IsNullOrEmpty(responseBodyText) ? JsonConvert.SerializeObject(responseBodyText) : null,
Elapsed = duration,
Status = context.Response.StatusCode.ToString(),
CreateUserId = userId,
UpdatePreData = updatePreData,
UpdateBefData = updateBefData,
Browser = browser,
Os = os,
DeviceType = deviceType,
};
// 存储到数据库
await _sqlSugar.Insertable(logInfo).ExecuteCommandAsync();
}
else
{
await _next(context);
}
}
private async Task TableInfoToJson(string tableName, int id)
{
if (_sqlSugar.DbMaintenance.IsAnyTable(tableName))
{
string jsonLabel = string.Empty;
if (tableName.Equals("Crm_NewClientData"))
{
var info = await _sqlSugar.Queryable().FirstAsync(x => x.Id == id);
if (info != null)
{
EncryptionProcessor.DecryptProperties(info);
if (info != null) jsonLabel = JsonConvert.SerializeObject(info);
}
}
else
{
var sql = string.Format(" Select * From {0} Where Id={1}", tableName, id);
var info = await _sqlSugar.SqlQueryable(sql).FirstAsync();
if (info != null) jsonLabel = JsonConvert.SerializeObject(info);
}
return jsonLabel;
}
return string.Empty;
}
private async Task ReadRequestBody(HttpRequest request)
{
request.EnableBuffering();
using var reader = new StreamReader(
request.Body,
Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: 8192,
leaveOpen: true
);
var body = await reader.ReadToEndAsync();
request.Body.Position = 0;
return body;
}
private async Task ReadResponseBody(Stream stream)
{
using var reader = new StreamReader(
stream,
Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: 8192,
leaveOpen: true
);
var body = await reader.ReadToEndAsync();
stream.Position = 0;
return body;
}
private async Task ReadToken(HttpContext context)
{
var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
// 检查Authorization头是否存在且以"Bearer "开头
if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
{
var authInfo = JwtHelper.SerializeJwt(authHeader);
if (authInfo != null) return authInfo.UserId;
}
return 0;
}
///
/// 获取IP信息
///
/// ipv4 or ipv6
///
private async Task<(string ip, string local)> GetIpInfo(string ip)
{
string local = string.Empty;
if (IPAddress.TryParse(ip,out _))
{
var response = await _httpClient.GetAsync($"https://api.vore.top/api/IPdata?ip={ip}");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var ipInfo = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
if (ipInfo.code == 200)
{
ip = ipInfo.ipinfo.text;
local = $"{ipInfo.adcode.o}";
}
}
return (ip, local);
}
private async Task GetExternalIp()
{
var response = await _httpClient.GetAsync("https://ifconfig.me");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
private async Task GetIpLocation(string ip)
{
var response = await _httpClient.GetAsync($"https://ipinfo.io/{ip}/json?&language=zh-CN");
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
var ipInfo = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
return $"{ipInfo.country}, {ipInfo.city}";
}
}
}