基于KYSharpCore+mysql的数据审计
该项目仅适用于本公司内部,所引用nuget不对外。
nuget引用版本:
KySharpCode 1.1 版本,
KYSharpCore.EntityFrameWork.MySql 3.1.7.4 版本
=====================================================================
数据审计包含范围很广,此次升级主要是针对应用内的数据审计。如在应用内对数据进行增删改操作的审计。
数据底层具体操作方式,详见:https://www.cnblogs.com/fei686868/articles/12221983.html
审计部分涉及的实体类包含(均在kysharpcore基类中)
AuditOperationEntry :主要记录操作的时间、用户、IP、url、客户端浏览器信息,该类嵌套AuditEntityEntry 数组。
AuditEntityEntry:主要记录实体信息,包含实体的名称、操作类型、主键,该类嵌套 AuditPropertyEntry数组。
AuditPropertyEntry:主要记录字段信息,包含字段的名称、类型、变更前后的数据。
其中AuditEntityEntry和AuditPropertyEntry的数据均在底层中获取。
所有需要审计的实体,均需要继承 IAudited 接口(命名空间:KYSharpCore.Audit),未继承的实体类,不会做审计。
如: public class Project : EntityBase<string>, IAudited
特别提示:存储审计的表对应的实体,不需要继承IAudited ,避免陷入死循环。
对于Update操作,获取数据需使用Track。若查询是AsNoTracking,将获取不到前后的变化。
当数据字段前后没变化时,也会获取审计实体信息,只是字段属性为null而已。实际存储,可根据需要自行处理。
下面详细讲讲用法:
1、定义一个action过滤器,主要用来获取AuditOperationEntry信息。例如:
public class AuditOperationAttribute : ActionFilterAttribute { private AuditOperationEntry _auditOperationEntry; private IAuditStore _auditStore; public AuditOperationAttribute(AuditOperationEntry auditOperationEntry, IAuditStore auditStore) { _auditOperationEntry = auditOperationEntry; _auditStore = auditStore; } /// <inheritdoc /> public override void OnActionExecuting(ActionExecutingContext context) { // IServiceProvider provider = context.HttpContext.RequestServices; _auditOperationEntry.Ip = GetClientIp(context.HttpContext); _auditOperationEntry.UserAgent = context.HttpContext.Request.Headers["User-Agent"].FirstOrDefault(); _auditOperationEntry.CreatedTime = DateTime.Now; _auditOperationEntry.UserId = "111"; //需要根据系统获取 _auditOperationEntry.UserName = "张三"; _auditOperationEntry.NickName = "三儿"; _auditOperationEntry.PageUrl = context.HttpContext.Request.GetDisplayUrl(); _auditOperationEntry.FunctionName = GetFunctionName(context); } /// <summary> /// 获取Area名 /// </summary> public string GetFunctionName(ActionContext context) { string area = ""; string controller = ""; string action = ""; if (context.RouteData.Values.TryGetValue("area", out object value)) { area = (string)value; if (string.IsNullOrWhiteSpace(area)) { area = null; } } controller= context.RouteData.Values["controller"].ToString(); action= context.RouteData.Values["action"].ToString(); return (area+"/"+controller+"/"+action).Trim('/'); } /// <summary> /// 获取客户端IP地址 /// </summary> public static string GetClientIp(HttpContext context) { string ip = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); if (string.IsNullOrEmpty(ip)) { ip = context.Connection.RemoteIpAddress.ToString(); } return ip; } ///// <inheritdoc /> public override void OnResultExecuted(ResultExecutedContext context) { IServiceProvider provider = context.HttpContext.RequestServices; _auditOperationEntry.EndedTime = DateTime.Now; if (_auditStore != null&& _auditOperationEntry.EntityEntries.Any()) { _auditStore.Save(_auditOperationEntry); //调用注入的审计存储方法 } } }
2、在Startup.cs中增加注入,如下:
public void ConfigureServices(IServiceCollection services) { //注册默认数据库 services.AddKYSharpCoreDbContext(Configuration); services.AddScoped<AuditOperationEntry>(); //审计必须的 services.AddScoped<IAuditStore, AuditStore>();//审计必须的,AuditStore类是对IAuditStore接口的实现,需要各应用端自行实现。 services.AddControllersWithViews( o => { o.Filters.Add(typeof(AuditOperationAttribute)); //审计需要,注入过滤器获取登录信息 }); }
3、实现审计的存储
/// <summary> /// 处理审计的存储 /// </summary> public class AuditStore : IAuditStore { public void Save(AuditOperationEntry operationEntry) { //这里接收AuditOperationEntry对象参数,里面包含所有审计数据,自行存储到数据库。存储方式自行选择 } public Task SaveAsync(AuditOperationEntry operationEntry, CancellationToken cancelToken = default) { //这里接收AuditOperationEntry对象参数,里面包含所有审计数据,自行存储到数据库。存储方式自行选择 return null; } }
按照上述方式进行操作,即可对系统中所有继承IAudited接口的实体类对应的数据表的增删改操作记录审计日志。