using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Diagnostics; using System.IdentityModel.Tokens.Jwt; using System.IO; using System.Linq; using System.Security.Claims; using System.Text; using System.Threading.Tasks; using System.Web; using CoreCms.Net.Configuration; using CoreCms.Net.Filter; using CoreCms.Net.IServices; using CoreCms.Net.Loging; using CoreCms.Net.Model.Entities; using CoreCms.Net.Model.ViewModels.Basics; using CoreCms.Net.Utility.Extensions; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.JwtBearer; namespace CoreCms.Net.Middlewares { /// /// 中间件 /// 记录用户方访问数据 /// public class RecordAccessLogsMildd { private readonly RequestDelegate _next; private readonly IHttpContextAccessor _httpContextAccessor; private readonly ISysUserOperationLogServices _sysUserOperationLogServices; private readonly Stopwatch _stopwatch; private readonly string _dataSources; /// /// 构造 /// public RecordAccessLogsMildd(RequestDelegate next, IHttpContextAccessor httpContextAccessor, ISysUserOperationLogServices sysUserOperationLogServices, string dataSources) { _next = next; _httpContextAccessor = httpContextAccessor; _dataSources = dataSources; _sysUserOperationLogServices = sysUserOperationLogServices; _stopwatch = new Stopwatch(); } public async Task InvokeAsync(HttpContext context) { //用户访问记录-是否开启 var middlewareRecordAccessLogsEnabled = AppSettingsConstVars.MiddlewareRecordAccessLogsEnabled; //是否开启记录到文件模式 var middlewareRecordAccessLogsEnabledFileMode = AppSettingsConstVars.MiddlewareRecordAccessLogsEnabledFileMode; //是否开启记录到数据库模式 var middlewareRecordAccessLogsEnabledDbMode = AppSettingsConstVars.MiddlewareRecordAccessLogsEnabledDbMode; if (middlewareRecordAccessLogsEnabled && (middlewareRecordAccessLogsEnabledFileMode || middlewareRecordAccessLogsEnabledDbMode)) { var request = context.Request; var api = request.Path.ObjectToString().TrimEnd('/').ToLower(); var ignoreApis = AppSettingsConstVars.MiddlewareRecordAccessLogsIgnoreApis; // 过滤,只有接口 if (api.Contains("api") && !ignoreApis.ToLower().Contains(api)) { _stopwatch.Restart(); var uLog = new SysUserOperationLog(); if (_httpContextAccessor.HttpContext != null) { var authenticate = await _httpContextAccessor.HttpContext.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme); if (authenticate.Succeeded && authenticate.Principal != null) { //账号 uLog.userName = authenticate.Principal.Identities.First().FindFirst(ClaimTypes.Name)?.Value; //昵称 uLog.userNickName = authenticate.Principal.Identities.First().FindFirst(ClaimTypes.GivenName)?.Value; //用户序列 uLog.userId = authenticate.Principal.Identities.First().FindFirst(JwtRegisteredClaimNames.Jti)!.Value.ObjectToInt(0); } var adminLog = AdminsControllerPermission.GetCacheCoreCmsActionPermission(_dataSources); var curLog = adminLog.FirstOrDefault(p => p.path.ToLower() == _httpContextAccessor.HttpContext.Request.Path.Value.ToLower()); if (curLog != null) { uLog.actionName = curLog.actionName; uLog.actionDescription = curLog.description; uLog.controllerName = curLog.controllerName; uLog.controllerDescription = curLog.controllerDescription; } uLog.apiPath = _httpContextAccessor.HttpContext.Request.Path.Value; uLog.statusCode = _httpContextAccessor.HttpContext.Response.StatusCode; } else { uLog.apiPath = api; } uLog.ip = IPLogMildd.GetClientIp(context); uLog.beginTime = DateTime.Now; uLog.requestMethod = request.Method; uLog.agent = request.Headers["User-Agent"].ObjectToString(); uLog.dataSources = _dataSources; switch (request.Method.ToLower()) { // 获取请求body内容 case "post": case "put": { // 启用倒带功能,就可以让 Request.Body 可以再次读取 request.EnableBuffering(); var stream = request.Body; if (request.ContentLength != null) { byte[] buffer = new byte[request.ContentLength.Value]; var read = await stream.ReadAsync(buffer); uLog.requestData = Encoding.UTF8.GetString(buffer); } request.Body.Position = 0; break; } case "get": case "delete": uLog.requestData = HttpUtility.UrlDecode(request.QueryString.ObjectToString(), Encoding.UTF8); break; } // 获取Response.Body内容 var originalBodyStream = context.Response.Body; await using (var responseBody = new MemoryStream()) { context.Response.Body = responseBody; await _next(context); uLog.responseBodyData = await GetResponse(context.Response); await responseBody.CopyToAsync(originalBodyStream); } // 响应完成记录时间和存入日志 context.Response.OnCompleted(async () => { _stopwatch.Stop(); uLog.opTime = _stopwatch.ElapsedMilliseconds + "ms"; uLog.endTime = DateTime.Now; uLog.createTime = DateTime.Now; //写入文件 if (middlewareRecordAccessLogsEnabledFileMode) { // 自定义log输出 var requestInfo = JsonConvert.SerializeObject(uLog); Parallel.For(0, 1, e => { LogLockHelper.OutSql2Log("RecordAccessLogs", "RecordAccessLogs" + DateTime.Now.ToString("yyyy-MM-dd-HH"), new[] { requestInfo + "," }, false); }); } //写入数据库 if (middlewareRecordAccessLogsEnabledDbMode) { await _sysUserOperationLogServices.InsertAsync(uLog); } }); } 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; } } }