LEIYI 3 meses atrás
pai
commit
ca956f4fff

+ 1 - 1
OASystem/OASystem.Api/Controllers/AuthController.cs

@@ -80,7 +80,7 @@ namespace OASystem.API.Controllers
         /// <returns></returns>
         [Route("login")]
         [HttpPost]
-        [ApiLog("Login",OperationEnum.Login)]
+        [ApiLog("Login", OperationEnum.Login)]
         [ProducesResponseType(typeof(LoginView), StatusCodes.Status200OK)]
         public async Task<IActionResult> LoginAsync(LoginDto dto)
         {

+ 179 - 16
OASystem/OASystem.Api/Middlewares/RecordAPIOperationMiddleware.cs

@@ -1,12 +1,17 @@
-using Aspose.Words;
+using AlibabaCloud.OpenApiClient.Models;
+using Aspose.Words;
 using NPOI.HSSF.Record;
+using OASystem.API.OAMethodLib;
 using OASystem.Domain.Attributes;
 using OASystem.Domain.Entities.Customer;
 using OASystem.Infrastructure.Repositories.CRM;
 using System.ComponentModel.DataAnnotations;
 using System.Diagnostics;
-using XAct;
 using static Google.Protobuf.Reflection.SourceCodeInfo.Types;
+using static OASystem.API.OAMethodLib.JWTHelper;
+using UAParser;
+using System.Collections.Generic;
+using XAct;
 
 namespace OASystem.API.Middlewares
 {
@@ -42,6 +47,64 @@ namespace OASystem.API.Middlewares
             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;
+                        var requestBodyJson = JsonConvert.DeserializeObject<Dictionary<string, object>>(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);
+
+                        if (!string.IsNullOrEmpty(param1.ToString())) 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<Sys_Users>().Where(x => x.IsDel == 0 && x.Number.Equals(number)).FirstAsync();
+                                    userId = info.Id;
+                                }
+                            }
+                            else
+                            {
+                                if (int.TryParse(param2.ToString(), out userId)) { }
+                                else if (int.TryParse(param3.ToString(), out userId)) { }
+                                else if (int.TryParse(param4.ToString(), out userId)) { }
+                            }
+                        }
+                        //编辑前数据查询;
+                        if (param5 != null) if (!string.IsNullOrEmpty(param5.ToString())) param5Bool = int.TryParse(param5.ToString(), out id);
+
+                        if (param6 != null) if (!string.IsNullOrEmpty(param6.ToString())) param6Bool = int.TryParse(param6.ToString(), out status);
+
+                        if (param6Bool)
+                        {
+                            //  2 修改 
+                            if (status == 2) updatePreData = await TableInfoToJson(apiLogAttribute.TableName, id);
+                        }
+                        else if (param5Bool)
+                        {
+                            //  id > 0 修改 
+                            if (id > 0) updatePreData = await TableInfoToJson(apiLogAttribute.TableName, id);
+                        }
+                    }
+                }
+                catch (JsonException) { }
 
                 // 保存原始响应体流
                 var originalResponseBody = context.Response.Body;
@@ -53,31 +116,89 @@ namespace OASystem.API.Middlewares
                 // 调用下一个中间件
                 await _next(context);
 
-                // 读取响应体内容
-                var responseBodyText = await new StreamReader(responseMemoryStream).ReadToEndAsync();
-
                 // 重置响应体流的位置
                 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)
+                {
+                    //  id > 0 修改 
+                    if (id > 0) updateBefData = await TableInfoToJson(apiLogAttribute.TableName, id);
+                }
+                string remoteIp = context.Connection.RemoteIpAddress?.ToString(), 
+                       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];
+                }
+
+                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;
 
-                int portType = 1;
-
                 var logInfo = new Crm_TableOperationRecord() {
                     TableName = apiLogAttribute.TableName,
                     PortType = portType,
                     OperationItem = apiLogAttribute.OperationEnum,
                     DataId = apiLogAttribute.DataId,
                     RequestUrl = context.Request.Path,
-                    RequestParam = requestBodyText,
-                    ReturnResult = responseBodyText,
+                    RemoteIp = remoteIp,
+                    Location = location,
+                    RequestParam =!string.IsNullOrEmpty(requestBodyText) ? JsonConvert.SerializeObject(requestBodyText) : null,
+                    ReturnResult = !string.IsNullOrEmpty(responseBodyText) ? JsonConvert.SerializeObject(requestBodyText) : null,
                     Elapsed = duration,
                     Status = context.Response.StatusCode.ToString(),
-
+                    CreateUserId = userId,
+                    UpdatePreData = updatePreData,
+                    UpdateBefData = updateBefData,
+                    Browser= browser,
+                    Os = os,
+                    DeviceType = deviceType,
                 };
 
                 // 存储到数据库
@@ -85,26 +206,68 @@ namespace OASystem.API.Middlewares
             }
             else
             {
-                // 调用下一个中间件
                 await _next(context);
             }
         }
 
+        private async Task<string> TableInfoToJson(string tableName,int id)
+        {
+            if (_sqlSugar.DbMaintenance.IsAnyTable(tableName))
+            {
+                var info = await _sqlSugar.Queryable<dynamic>(tableName).Where("id=@id", new { id = id }).FirstAsync();
+                return JsonConvert.SerializeObject(info);
+            }
+
+            return string.Empty;
+        }
+
         private async Task<string> ReadRequestBody(HttpRequest request)
         {
             request.EnableBuffering();
 
-            // 读取请求体内容
-            using var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true);
-            var requestBodyText = await reader.ReadToEndAsync();
+            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<string> ReadResponseBody(Stream stream)
+        {
+            using var reader = new StreamReader(
+                stream,
+                Encoding.UTF8,
+                detectEncodingFromByteOrderMarks: false,
+                bufferSize: 8192,
+                leaveOpen: true
+            );
 
-            return requestBodyText;
+            var body = await reader.ReadToEndAsync();
+            stream.Position = 0;
+            return body;
         }
 
 
+        private async Task<int> 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;
+        }
+
         private async Task<string> GetExternalIp()
         {
             var response = await _httpClient.GetAsync("https://ifconfig.me");

+ 1 - 0
OASystem/OASystem.Api/OASystem.API.csproj

@@ -60,6 +60,7 @@
     <PackageReference Include="TencentCloudSDK.Common" Version="3.0.734" />
     <PackageReference Include="TencentCloudSDK.Ocr" Version="3.0.734" />
     <PackageReference Include="TinyPinyin.Net" Version="1.0.2" />
+    <PackageReference Include="UAParser" Version="3.1.47" />
   </ItemGroup>
 	
   <ItemGroup>

+ 5 - 0
OASystem/OASystem.Domain/Entities/Customer/Crm_TableOperationRecord.cs

@@ -54,6 +54,11 @@ namespace OASystem.Domain.Entities.Customer
         /// </summary>
         public string? Location { get; set; }
 
+        /// <summary>
+        /// 设备类型
+        /// </summary>
+        public string DeviceType { get; set; }
+
         /// <summary>
         /// 浏览器
         /// </summary>