实体类:
public class ApiActionDescriptorModel:ICloneable { public string ActionName { get; set; } public string ControllerName { get; set; } public ApiParameterDescriptorModel[] Parameters { get; set; } public ApiReturnAttributeModel[] apiReturnAttributes { get; set; } public string RequestIp { get; set; } public string HttpMethod { get; set; } public string RequestPort { get; set; } public long ExecutTime { get; set; } public string Operator { get; set; } public DateTime OperaTime { get; set; } public string RequestBody { get; set; } public string QueryString { get; set; } public string ResposeBody { get; set; } public int ResposeStatusCode { get; set; } public string UserId { get; set; } public object Clone() { return new ApiActionDescriptorModel { ActionName = this.ActionName, RequestIp = this.RequestIp, HttpMethod = this.HttpMethod, RequestPort = this.RequestPort, ExecutTime = this.ExecutTime, Parameters = this.Parameters.Select(t => (ApiParameterDescriptorModel)t.Clone()).ToArray() }; } }
过滤器:
public class ExceptionFilter : IExceptionFilter { [Import] private ILoggerHelper loggerHelper { get; set; } public ExceptionFilter(IoC ioc) { ioc.Compose(this); } public void OnException(ExceptionContext context) { if (context.ExceptionHandled == false) { var jsonobj = Dr.Soc.Common.Helpers.JsonResult.Error(context.Exception.Message); context.Result = new JsonResult(jsonobj); } loggerHelper.Error($"全局捕获异常:" + context.Exception.ToString()+"====="+ "入参参数:"+ GetExceptionRequestBody(context)+context?.HttpContext?.Request?.QueryString); context.ExceptionHandled = true; } public Task OnExceptionAsync(ExceptionContext context) { OnException(context); return Task.CompletedTask; } private string GetExceptionRequestBody(ExceptionContext context) { string requestBody = ""; if (context != null) { var request = context?.HttpContext?.Request; if (request != null) { request.Body.Position = 0; StreamReader stream = new StreamReader(request.Body); requestBody = stream.ReadToEnd(); request.Body.Position = 0; } } return requestBody; } }
public class ActionFilter : IActionFilter { private Stopwatch timer; [Import] private IAduitService aduitService { get; set; } public ActionFilter(IoC ioc) { ioc.Compose(this); } public void OnActionExecuting(ActionExecutingContext context) { this.timer = new Stopwatch(); this.timer.Start(); } public void OnActionExecuted(ActionExecutedContext context) { this.timer.Stop(); aduitService.HandleApiAction(GetActionDescriptor(context)); } private ApiActionDescriptorModel GetActionDescriptor(ActionExecutedContext context) { ApiActionDescriptorModel descriptor = new ApiActionDescriptorModel(); var userInfo= ((System.Security.Claims.ClaimsIdentity)context.HttpContext.User.Identity).Claims?.ToList(); if (context != null) { descriptor.ActionName = ((ControllerActionDescriptor)context.ActionDescriptor)?.ActionName; descriptor.ControllerName = ((ControllerActionDescriptor)context.ActionDescriptor)?.ControllerName; descriptor.RequestIp = context.HttpContext.Request.Host.Host.ToString(); descriptor.RequestPort = context.HttpContext.Request.Host.Port.ToString(); descriptor.HttpMethod = context.HttpContext.Request.Method.ToString(); descriptor.ExecutTime = this.timer.ElapsedMilliseconds; descriptor.Operator = userInfo?.Where(t => t.Type == "UserName")?.FirstOrDefault()?.Value; descriptor.UserId = userInfo?.Where(t => t.Type == "UserId")?.FirstOrDefault()?.Value; descriptor.OperaTime = DateTime.Now; descriptor.RequestBody = ReadActionExcutedRequestBody(context); descriptor.QueryString = context.HttpContext.Request?.QueryString.ToString(); descriptor.ResposeBody = GetActionExcutedResponseBody(context); descriptor.ResposeStatusCode = context.HttpContext.Response.StatusCode; } return descriptor; } private string ReadActionExcutedRequestBody(ActionExecutedContext context) { string requestBody = ""; if (context != null) { var request = context.HttpContext.Request; request.Body.Position = 0; StreamReader stream = new StreamReader(request.Body); requestBody = stream.ReadToEnd(); request.Body.Position = 0; } return requestBody; } private string GetActionExcutedResponseBody(ActionExecutedContext context) { string responseBody = ""; if (context.Result != null) { if (context.Result is ObjectResult) responseBody = JsonConvert.SerializeObject(((ObjectResult)context.Result).Value); if (context.Result is JsonResult) responseBody = JsonConvert.SerializeObject(((JsonResult)context.Result).Value); } return responseBody; } }
在startup中注册:
app.Use(next => new RequestDelegate( async context => { context.Request.EnableBuffering(); await next(context); } ));
就可以在请求之后获取到请求体了。
public async Task<bool> HandleApiAction(ApiActionDescriptorModel apiActionDescriptorModel) { bool result = false; var cacheAuditRule = auditRuleLoader.GetAllAuditRule(); try { if (cacheAuditRule == null || cacheAuditRule.Count == 0) return result; if (string.IsNullOrEmpty(apiActionDescriptorModel?.RequestBody) || string.IsNullOrEmpty(apiActionDescriptorModel?.ActionName) || string.IsNullOrEmpty(apiActionDescriptorModel?.ControllerName) || string.IsNullOrEmpty(apiActionDescriptorModel?.HttpMethod)) return result; List<AuditModel> list = HandleApiAction(apiActionDescriptorModel, cacheAuditRule); if (list == null || list.Count == 0) return result; result = await auditDataAccessor.BatchAddAudit(list.Adapt<List<AuditDao>>()).ConfigureAwait(false); return result; } catch (Exception ex) { loggerHelper.Error(apiActionDescriptorModel.ControllerName + apiActionDescriptorModel.ActionName + "插入审计失败,失败原因:" + ex.ToString()); return result; } } private List<AuditModel> HandleApiAction(ApiActionDescriptorModel apiActionDescriptorModel, List<AuditRuleModel> auditRuleModels) { int apiEnum = (int)EnumHelper.GetValue(typeof(HttpMethodEnum), apiActionDescriptorModel.HttpMethod?.ToLower()); var auditRuleModel = auditRuleModels.Where(t => t.ControllerName == apiActionDescriptorModel.ControllerName && t.ActionName == apiActionDescriptorModel.ActionName && t.HttpMethod == apiEnum)?.FirstOrDefault(); List<AuditModel> list = new List<AuditModel>(); if (auditRuleModel == null) return list; if (!string.IsNullOrEmpty(auditRuleModel.AuditRuleDescr)) { var audits = GetAudits(apiActionDescriptorModel, auditRuleModel); if (audits != null && audits.Count > 0) list = GetAudits(apiActionDescriptorModel, auditRuleModel, audits); } return list; } private List<AuditModel> GetAudits(ApiActionDescriptorModel apiActionDescriptorModel, AuditRuleModel auditRuleModel, List<string> audits) { List<AuditModel> auditModels = new List<AuditModel>(); int responseCode = GetResponseCode(apiActionDescriptorModel?.ResposeBody); for (int i = 0; i < audits.Count; i++) { AuditModel auditModel = new AuditModel(); auditModel.UserName = apiActionDescriptorModel.Operator; auditModel.AddTime = apiActionDescriptorModel.OperaTime; auditModel.Ip = apiActionDescriptorModel.RequestIp.Replace("localhost", "127.0.0.1"); auditModel.ResponseCode = responseCode; auditModel.ModelType = auditRuleModel.ModelType; auditModel.Type = EnumHelper.Parse<OperateType>(auditRuleModel.OperateType); auditModel.IncidenceLevel = EnumHelper.Parse<IncidenceLevel>(auditRuleModel.IncidenceLevel); auditModel.Detail = audits[i]; auditModel.UserId = apiActionDescriptorModel.UserId; auditModel.UserName = apiActionDescriptorModel.Operator; auditModels.Add(auditModel); } return auditModels; } private List<string> GetAudits(ApiActionDescriptorModel apiActionDescriptorModel, AuditRuleModel auditRuleModel) { var jsonDics = GetKeyValues(apiActionDescriptorModel.RequestBody); var urlDics = GetKeyValues(apiActionDescriptorModel.QueryString); foreach (var item in urlDics) { if (item != null && item.Count > 0) { foreach (var keyValue in item) jsonDics.ForEach(t => t.Add(keyValue.Key, keyValue.Value)); } } List<string> audits = new List<string>(); foreach (var item in jsonDics) { var ruleStr = auditRuleModel.AuditRuleDescr; string[] rules = RegularHelper.FindByRegexRemoveRegexs(ruleStr, "【\${.*?}】", "[【】\${}]+"); if (rules.Length > 0) { for (int i = 0; i < rules.Length; i++) { if (!item.Keys.Contains(rules[i])) continue; string value = item[rules[i]]; if (rules[i] == auditRuleModel.AssetIdMappingField) value = assetAccountLoader.GetAssetCacheByCode(value).Name; ruleStr = ruleStr.Replace("${" + rules[i] + "}", value); } } audits.Add(ruleStr); } return audits; } private List<Dictionary<string, string>> GetKeyValues(string txt) { List<Dictionary<string, string>> dics = new List<Dictionary<string, string>>(); if (JsonHelper.StringIsJson(txt)) { string text = RegularHelper.FindFirstByRegex(txt, @"^[.*?]$"); List<JObject> jObjects = string.IsNullOrEmpty(text) ? new List<JObject>() { JsonConvert.DeserializeObject<JObject>(txt) } : JsonConvert.DeserializeObject<List<JObject>>(txt); foreach (var item in jObjects) dics.Add(item.Properties().ToDictionary(x => x.Name, y => y.Value.ToString())); } else { NameValueCollection collection = HttpUtility.ParseQueryString(txt); var dic = new Dictionary<string, string>(); foreach (var item in collection.AllKeys) dic.Add(item, collection[item]); dics.Add(dic); } return dics; } private static int GetResponseCode(string resposeBody) { int responseCode = -1; int.TryParse(RegularHelper.FindContentBetweenTwoRegex(resposeBody, "code":", ","), out responseCode); return responseCode; } private List<AuditModel> HandleIsJsonActionToAudit(ApiActionDescriptorModel apiActionDescriptorModel, AuditRuleModel auditRuleModel) { string text = RegularHelper.FindFirstByRegex(apiActionDescriptorModel.RequestBody, @"^[.*?]$"); List<JObject> jObjects = null; if (!string.IsNullOrEmpty(text)) jObjects = JsonConvert.DeserializeObject<List<JObject>>(apiActionDescriptorModel.RequestBody); else jObjects = new List<JObject>() { JsonConvert.DeserializeObject<JObject>(apiActionDescriptorModel.RequestBody) }; string[] rules = RegularHelper.SplitByRegex(auditRuleModel.AuditRuleDescr, "【.*?】"); List<AuditModel> list = null; for (int i = 0; i < jObjects.Count; i++) { list = new List<AuditModel>(){ new AuditModel() { UserName=apiActionDescriptorModel.Operator, ModelType=auditRuleModel.ModelType, Type =EnumHelper.Parse<OperateType>(auditRuleModel.OperateType), IncidenceLevel =EnumHelper.Parse<IncidenceLevel>(auditRuleModel.IncidenceLevel), UserId=apiActionDescriptorModel.UserId, Detail = GetAuditDetailByRuleRule(jObjects[i], rules).ToString(), AddTime = apiActionDescriptorModel.OperaTime, Ip = apiActionDescriptorModel.RequestIp.Replace("localhost","127.0.0.1"), ResponseCode=GetResponseCode(apiActionDescriptorModel?.ResposeBody), } }; } return list; } private List<AuditModel> HandleNotJsonActionToAduit(ApiActionDescriptorModel apiActionDescriptorModel, AuditRuleModel auditRuleModel) { string[] rules = RegularHelper.SplitByRegex(auditRuleModel.AuditRuleDescr, "【.*?】"); List<AuditModel> list = null; if (rules.Length >= 2) { list = new List<AuditModel>(){ new AuditModel() { UserName=apiActionDescriptorModel.Operator, ModelType=auditRuleModel.ModelType, Type =EnumHelper.Parse<OperateType>(auditRuleModel.OperateType), IncidenceLevel =EnumHelper.Parse<IncidenceLevel>(auditRuleModel.IncidenceLevel), Detail = GetAuditDetailByRuleRule(apiActionDescriptorModel.RequestBody,rules).ToString(), AddTime = apiActionDescriptorModel.OperaTime, Ip = apiActionDescriptorModel.RequestIp.Replace("localhost","127.0.0.1"), ResponseCode=GetResponseCode(apiActionDescriptorModel?.ResposeBody), } }; } return list; } private StringBuilder GetAuditDetailByRuleRule(string text, string[] rules) { StringBuilder sb = new StringBuilder(); sb.Append(rules[0]); for (int i = 1; i < rules.Length; i++) sb.Append( RegularHelper.RegexReplace( rules[i], "【.*?】", "【" + RegularHelper.FindContentBetweenTwoRegex( text, "[\?&]" + RegularHelper.FindContentBetweenTwoRegex(rules[i], @"【${", "}】") + "=", "(&|$)") + "】" )); return sb; } private StringBuilder GetAuditDetailByRuleRule(JObject jObject, string[] rules) { StringBuilder sb = new StringBuilder(); sb.Append(rules[0]); for (int i = 1; i < rules.Length; i++) { try { sb.Append( RegularHelper.RegexReplace(rules[i], "【.*?】", "【" + jObject[RegularHelper.FindContentBetweenTwoRegex(rules[i], @"【${", "}】")].ToString() + "】" )); } catch (Exception ex) { loggerHelper.Error("在" + rules[i] + "查找失败,具体原因:" + ex.ToString()); throw; } } return sb; }
public static string[] FindByRegexRemoveRegexs(string html, string strReg, string remReg) { string[] strs = FindByRegex(html, strReg); List<string> result = new List<string>(); if (strs.Length > 0) { for (int i = 0; i < strs.Length; i++) result.Add(RemoveByRegex(strs[i], remReg)); } return result.ToArray(); }