实体类:
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();
}