using Admin.Core.Common; using Admin.Core.IService.ISys; using Admin.Core.Model.Sys; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; using System.Diagnostics; using System.IO; using System.Text; using System.Threading.Tasks; using System.Web; namespace Admin.Core.Extensions { /// /// 中间件 /// 记录用户方访问数据 /// public class RecordAccessLogsMildd { /// /// RequestDelegate /// private readonly RequestDelegate _next; private readonly IUser _user; private readonly ILogger _logger; private readonly IWebHostEnvironment _environment; private readonly ISysOperLogService _sysOperLogService; private Stopwatch _stopwatch; /// /// RecordAccessLogsMildd /// /// public RecordAccessLogsMildd(RequestDelegate next, IUser user, ILogger logger, IWebHostEnvironment environment, ISysOperLogService sysOperLogService) { _next = next; _user = user; _logger = logger; _environment = environment; _sysOperLogService = sysOperLogService; _stopwatch = new Stopwatch(); } public async Task InvokeAsync(HttpContext context) { if (Appsettings.app("Middleware", "RecordAccessLogs", "Enabled").ObjToBool()) { var api = context.Request.Path.ObjToString().TrimEnd('/').ToLower(); var ignoreApis = Appsettings.app("Middleware", "RecordAccessLogs", "IgnoreApis"); // 过滤,只有接口 if (api.Contains("api") && !ignoreApis.Contains(api)) { _stopwatch.Restart(); var userAccessModel = new UserAccessModel(); HttpRequest request = context.Request; userAccessModel.API = api; userAccessModel.User = _user.Name; userAccessModel.Action = string.Empty; userAccessModel.Type = ActionType.OTHER; userAccessModel.IP = IpHelper.GetIpAddr(context); userAccessModel.BeginTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); userAccessModel.RequestMethod = request.Method; userAccessModel.Agent = request.Headers["User-Agent"].ObjToString(); // 获取请求body内容 if (request.Method.ToLower().Equals("post") || request.Method.ToLower().Equals("put")) { // 启用倒带功能,就可以让 Request.Body 可以再次读取 request.EnableBuffering(); Stream stream = request.Body; byte[] buffer = new byte[request.ContentLength.Value]; stream.Read(buffer, 0, buffer.Length); userAccessModel.RequestData = Encoding.UTF8.GetString(buffer); request.Body.Position = 0; } else if (request.Method.ToLower().Equals("get") || request.Method.ToLower().Equals("delete")) { userAccessModel.RequestData = HttpUtility.UrlDecode(request.QueryString.ObjToString(), Encoding.UTF8); } // 获取Response.Body内容 var originalBodyStream = context.Response.Body; using (var responseBody = new MemoryStream()) { context.Response.Body = responseBody; await _next(context); var responseBodyData = await GetResponse(context.Response); userAccessModel.ResponseBody = responseBodyData; await responseBody.CopyToAsync(originalBodyStream); } // 响应完成记录时间和存入日志 context.Response.OnCompleted(() => { _stopwatch.Stop(); if (!request.Method.ToLower().Equals("options")) { userAccessModel.OPTime = _stopwatch.ElapsedMilliseconds.ToString(); if ((request.Method.ToLower().Equals("post") || request.Method.ToLower().Equals("put") || request.Method.ToLower().Equals("get") || request.Method.ToLower().Equals("delete"))) { //获取Controller自定义属性 var endpoint = GetEndpoint(context); if (endpoint != null) { var actionAttribute = endpoint.Metadata.GetMetadata(); if (actionAttribute != null) { userAccessModel.Action = actionAttribute.Title; userAccessModel.Type = actionAttribute.ActionType; _=LogDB(userAccessModel); } } } // 自定义log输出 var requestInfo = JsonConvert.SerializeObject(userAccessModel); //Parallel.For(0, 1, e => //{ // LogLock.OutSql2Log("RecordAccessLogs", new string[] { requestInfo + "," }, false); //}); var logFileName = FileHelper.GetAvailableFileNameWithPrefixOrderSize(_environment.ContentRootPath, "RecordAccessLogs"); SerilogServer.WriteLog(logFileName, new string[] { requestInfo + "," }, false); } return Task.CompletedTask; }); } else { await _next(context); } } else { await _next(context); } } /// /// 获取响应内容 /// /// /// public async Task GetResponse(HttpResponse response) { response.Body.Seek(0, SeekOrigin.Begin); var text = await new StreamReader(response.Body).ReadToEndAsync(); response.Body.Seek(0, SeekOrigin.Begin); return text; } /// /// 获取Controller自定义属性 /// /// /// public static Endpoint GetEndpoint(HttpContext context) { if (context == null) { throw new ArgumentNullException(nameof(context)); } return context.Features.Get()?.Endpoint; } /// /// 用户操作日志记录入库 /// /// protected internal virtual async Task LogDB(UserAccessModel userAccess) { try { if (!userAccess.IsNotEmptyOrNull()) return; // *========数据库日志=========*// SysOperLog operLog = new SysOperLog(); operLog.Title = userAccess.Action; operLog.BusinessType = EnumHelper.ToInt(userAccess.Type); operLog.Method = userAccess.API.Substring(userAccess.API.LastIndexOf('/') + 1); operLog.RequestMethod = userAccess.RequestMethod; operLog.OperatorType = SysConst.USERTYPE_OTHER; operLog.OperName = userAccess.User; operLog.DeptName = string.Empty; operLog.OperUrl = userAccess.API; operLog.OperIP = userAccess.IP; operLog.OperLocation = AddressHelper.GetRealAddressByIP(operLog.OperIP); operLog.OperParam = userAccess.RequestData; operLog.JsonResult = userAccess.ResponseBody; operLog.Status = SysConst.OTHER; operLog.Msg = string.Empty; operLog.OPTimer = userAccess.OPTime; operLog.OperTime = DateTime.Now; if (userAccess.ResponseBody.IsNotEmptyOrNull()) { var model = JsonHelper.ParseFormByJson(userAccess.ResponseBody); if (model.IsNotEmptyOrNull()) { operLog.Status = model.success ? SysConst.SUCCESS : SysConst.FAIL; operLog.Msg = model.msg; } } await _sysOperLogService.AddAsync(operLog); } catch { } } } public class UserAccessModel { public string User { get; set; } public string Action { get; set; } public ActionType Type { get; set; } public string IP { get; set; } public string API { get; set; } public string BeginTime { get; set; } public string OPTime { get; set; } public string RequestMethod { get; set; } public string RequestData { get; set; } public string ResponseBody { get; set; } public string Agent { get; set; } } }