除了对 HTTP 请求有审计日志记录以外,ABP vNext 还提供了实体审计信息的记录功能
1、模块配置
类型(class)是否定义了AuditedAttribute,DisableAuditingAttribute,或派生于IAuditingEnabled,2)类型方法定义AuditedAttribute
添加Auditing的拦截器
[DependsOn( typeof(AbpDataModule), typeof(AbpJsonModule), typeof(AbpTimingModule), typeof(AbpSecurityModule), typeof(AbpThreadingModule), typeof(AbpMultiTenancyModule) )] public class AbpAuditingModule : AbpModule { public override void PreConfigureServices(ServiceConfigurationContext context) { context.Services.OnRegistred(AuditingInterceptorRegistrar.RegisterIfNeeded); } }
整个审计日志拦截器的大体流程如下:
- 首先是判定 MVC 审计日志过滤器是否进行处理。
- 再次根据特性,和类型进行二次验证是否应该创建审计日志信息。
- 根据调用信息,创建
AuditLogInfo
和AuditLogActionInfo
审计日志信息。 - 调用
StopWatch
的计时方法,如果出现了异常则将异常信息添加到刚才构建的AuditLogInfo
对象中。 - 无论是否出现异常,都会进入
finally
语句块,这个时候会调用StopWatch
实例的停止方法,并统计完成执行时间
ASP.NET Core 中间件
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { if (!ShouldWriteAuditLog(context)) { await next(context); return; } using (var scope = _auditingManager.BeginScope()) { try { await next(context); } finally { await scope.SaveAsync(); } } }
2、审计的配置信息AbpAuditingOptions
HideErrors:默认为true,auditing will not throw an exceptions and it will log it when an error occurred while saving AuditLog.
IsEnabled: 默认为true,是否启用审计日志功能
ApplicationName 审计日志的应用程序名称,默认值为 null;
IsEnabledForAnonymousUsers 是否为匿名请求记录审计日志默认值 true;
List<AuditLogContributor> 审计日志功能的协作者集合,默认添加了 AspNetCoreAuditLogContributor 实现。;
List<Type> IgnoredType 默认的忽略类型,主要在序列化时使用。
IEntityHistorySelectorList EntityHistorySelectors 实体类型选择器。
IsEnabledForGetRequests:是否为 Get 请求记录审计日志,默认值 false。
3、Info信息
1)AuditLogInfo 应用名称,用户Id,用户名,租户Id,租户名,扮演Id,扮演名,执行时间,客户端信息,AuditLogActionInfo列表,Exception列表
2)AuditLogActionInfo
3)EntityChangeInfo
4)EntityPropertyChangeInfo
4、审计类接口
IMayHaveCreator;IMustHaveCreator;IHasModificationTime;IHasCreationTime;IHasCreationTime;IHasDeletionTime
ICreationAuditedObject(IHasCreationTime,IMayHaveCreator)
IModificationAuditedObject(IHasModificationTime)
IDeletionAuditedObject(IHasDeletionTime)
IAuditedObject(ICreationAuditedObject,IModificationAuditedObject)
IFullAuditedObject(IAuditedObject,IDeletionAuditedObject)
发现是 DbContext 每次进行 SaveChanges/SaveChangesAsync
的时候,就会对实体进行审计字段自动赋值操作。
public interface IAuditPropertySetter { void SetCreationProperties(object targetObject); void SetModificationProperties(object targetObject); void SetDeletionProperties(object targetObject); }
5)IAuditingManager
它们分别是负责管理审计日志信息的 IAuditingManager
,负责创建审计日志信息的 IAuditingHelper
,还有统计接口执行时常的 Stopwatch
public interface IAuditingManager { [CanBeNull] IAuditLogScope Current { get; } IAuditLogSaveHandle BeginScope(); }
public interface IAuditLogSaveHandle : IDisposable { void Save(); Task SaveAsync(); }
构造出了一个可以被释放的 IAuditLogSaveHandle
对象。ABP vNext 这样做的目的,就是可以嵌套多个 Scope,即 只在某个范围内 才将审计日志记录下来。这种特性类似于 工作单元 的用法,
审计日志的序列化处理是在 IAuditingHelper
的默认实现内部被使用,可以看到构建审计日志的方法内部,通过自定义的序列化器来将 Action 的参数进行序列化处理,方便存储。
保存AuditLogInfo
protected virtual async Task SaveAsync(DisposableSaveHandle saveHandle) { BeforeSave(saveHandle); if (ShouldSave(saveHandle.AuditLog)) { await _auditingStore.SaveAsync(saveHandle.AuditLog); } }
IAuditingStore 存储 AuditLogInfo
[Dependency(TryRegister = true)] public class SimpleLogAuditingStore : IAuditingStore, ISingletonDependency { public ILogger<SimpleLogAuditingStore> Logger { get; set; } public SimpleLogAuditingStore() { Logger = NullLogger<SimpleLogAuditingStore>.Instance; } public void Save(AuditLogInfo auditInfo) { Logger.LogInformation(auditInfo.ToString()); } public Task SaveAsync(AuditLogInfo auditInfo) { Save(auditInfo); return Task.FromResult(0); } }
AsyncLocalAmbientDataContext是异步线程安全ConcurrentDictionary<string, AsyncLocal<object>>,它有GetData,SetData
AmbientDataContextAmbientScopeProvider<T>,则是周围上下文,你可以通过GetValue获取现在的Item,
BeginScope是创建新的Item,此Item是当前,一旦退出,又指向原来的item