ABP - 审计日志 [AuditedAttribute、IAuditingManager、EntityAuditingHelper]
审计日志
- 核心辅助类:
AuditedAttribute:标记类/方法记录审计日志。IAuditingManager:手动管理审计日志。EntityAuditingHelper:实体审计辅助(自动填充创建/修改时间)。
审计日志(Auditing)核心类示例与讲解
ABP的审计日志功能用于自动记录系统中关键操作的细节(如“谁在什么时间操作了什么数据”),核心价值是追溯操作源头、保障数据安全。以下针对AuditedAttribute、IAuditingManager、EntityAuditingHelper三个核心类,结合实际场景讲解用法:
一、AuditedAttribute:自动记录审计日志(声明式用法)
AuditedAttribute是最常用的审计工具,通过标记类或方法,让框架自动记录操作日志,无需手动编写日志代码。支持类级别(所有方法生效)和方法级别(单个方法生效)。
1. 类级别标记(所有方法自动审计)
using Volo.Abp.Auditing;
using Volo.Abp.Application.Services;
// 标记整个服务类,所有公共方法都会记录审计日志
[Audited]
public class BookAppService : ApplicationService
{
private readonly IRepository<Book, Guid> _bookRepo;
public BookAppService(IRepository<Book, Guid> bookRepo)
{
_bookRepo = bookRepo;
}
// 自动记录:谁(CreatorId)、何时(Time)、调用了此方法、输入参数(id)、返回结果(BookDto)
public async Task<BookDto> GetAsync(Guid id)
{
var book = await _bookRepo.GetAsync(id);
return ObjectMapper.Map<Book, BookDto>(book);
}
// 自动记录:新增操作的输入(CreateBookInput)、新增的书籍ID等
public async Task<BookDto> CreateAsync(CreateBookInput input)
{
var book = ObjectMapper.Map<CreateBookInput, Book>(input);
await _bookRepo.InsertAsync(book);
return ObjectMapper.Map<Book, BookDto>(book);
}
}
2. 方法级别标记(指定方法审计)
public class OrderAppService : ApplicationService
{
// 仅标记此方法,其他方法不审计(适合只需要追溯关键操作的场景)
[Audited]
public async Task<OrderDto> PayAsync(Guid orderId, decimal amount)
{
// 支付业务逻辑...
}
// 不标记,不记录审计日志(如普通查询操作)
public async Task<List<OrderDto>> GetUserOrdersAsync(Guid userId)
{
// 普通查询逻辑...
}
}
讲解
- 自动记录内容:框架会自动捕获「操作人ID、操作时间、方法名、输入参数、返回结果、执行时长」,无需手动传参。
- 排除敏感参数:若方法参数包含密码等敏感信息,可通过
[DisableAuditing]标记参数排除审计:public async Task ResetPasswordAsync( Guid userId, [DisableAuditing] string newPassword // 不记录密码到审计日志 ) { // 重置密码逻辑... } - 适用场景:大多数常规CRUD操作、支付/审批等关键业务操作,用
[Audited]可零代码实现审计追溯。
二、IAuditingManager:手动管理审计日志(编程式用法)
当需要自定义审计内容(如补充业务备注、记录非方法调用的操作)时,可通过IAuditingManager手动创建和提交审计日志,灵活度更高。
示例:手动记录自定义审计日志
using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection;
public class InventoryService : ITransientDependency
{
private readonly IAuditingManager _auditingManager;
private readonly IRepository<Inventory, Guid> _inventoryRepo;
// 注入IAuditingManager
public InventoryService(IAuditingManager auditingManager, IRepository<Inventory, Guid> inventoryRepo)
{
_auditingManager = auditingManager;
_inventoryRepo = inventoryRepo;
}
public async Task AdjustStockAsync(Guid productId, int adjustCount, string reason)
{
// 1. 开启审计日志(创建审计范围)
using (var auditingScope = _auditingManager.BeginScope())
{
try
{
// 2. 业务逻辑:调整库存
var inventory = await _inventoryRepo.GetAsync(x => x.ProductId == productId);
inventory.Stock += adjustCount;
await _inventoryRepo.UpdateAsync(inventory);
// 3. 自定义审计内容(补充业务信息)
var auditLog = auditingScope.Log;
auditLog.MethodName = "AdjustStockAsync"; // 手动指定方法名
auditLog.Comments = $"库存调整原因:{reason}"; // 补充业务备注
auditLog.ExtraProperties["ProductId"] = productId; // 额外记录产品ID
auditLog.ExtraProperties["BeforeStock"] = inventory.Stock - adjustCount; // 调整前库存
auditLog.ExtraProperties["AfterStock"] = inventory.Stock; // 调整后库存
// 4. 提交审计日志(若不调用,框架会在作用域结束时自动提交)
await auditingManager.SaveAsync(auditLog);
}
catch (Exception ex)
{
// 5. 异常时标记日志状态(可选)
auditingScope.Log.Exception = ex;
throw;
}
}
}
}
讲解
- 核心方法:
BeginScope():创建审计范围,所有在范围内的操作可被记录到同一条日志。SaveAsync(auditLog):手动提交日志(若不调用,框架会在using作用域结束时自动提交)。
- 自定义字段:通过
auditLog.ExtraProperties可添加任意业务相关的额外信息(如库存调整前后的值、操作原因),满足个性化追溯需求。 - 适用场景:非标准方法调用的操作(如定时任务调整数据、批量处理)、需要补充业务备注的关键操作。
三、EntityAuditingHelper:实体审计辅助(自动填充审计字段)
EntityAuditingHelper用于手动触发实体的审计字段填充(如CreationTime、CreatorId、LastModificationTime),通常在“框架自动填充失效”的场景下使用(如手动new的实体、非仓储操作的实体)。
示例:手动填充实体审计字段
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
using Volo.Abp.DependencyInjection;
public class CustomDataService : ITransientDependency
{
private readonly EntityAuditingHelper _auditingHelper;
private readonly ICurrentUser _currentUser;
private readonly MyCustomDbContext _dbContext; // 自定义数据库上下文
public CustomDataService(
EntityAuditingHelper auditingHelper,
ICurrentUser currentUser,
MyCustomDbContext dbContext)
{
_auditingHelper = auditingHelper;
_currentUser = currentUser;
_dbContext = dbContext;
}
public async Task AddCustomDataAsync(string dataContent)
{
// 1. 手动创建实体(未通过仓储,框架无法自动填充审计字段)
var customData = new CustomData
{
Content = dataContent
// 此时:CreationTime、CreatorId 等审计字段为默认值(如DateTime.MinValue、null)
};
// 2. 手动调用EntityAuditingHelper填充审计字段
_auditingHelper.SetCreationAuditProperties(
entity: customData,
currentUserId: _currentUser.Id // 传递当前用户ID(用于填充CreatorId)
);
// 3. 手动将实体添加到数据库(非仓储操作)
_dbContext.CustomDatas.Add(customData);
await _dbContext.SaveChangesAsync();
// 最终实体的审计字段:
// CreationTime = 当前时间
// CreatorId = 当前用户ID(如Guid.Parse("..."))
}
}
// 定义带审计字段的实体
public class CustomData : Entity<Guid>, IHasCreationTime, IHasCreator
{
public string Content { get; set; }
public DateTime CreationTime { get; set; } // 需手动填充的审计字段
public Guid? CreatorId { get; set; } // 需手动填充的审计字段
}
讲解
- 核心方法:
SetCreationAuditProperties(entity, currentUserId):填充“创建审计”字段(CreationTime、CreatorId)。SetModificationAuditProperties(entity, currentUserId):填充“修改审计”字段(LastModificationTime、LastModifierId)。SetDeletionAuditProperties(entity, currentUserId):填充“删除审计”字段(DeletionTime、DeleterId,适用于软删除)。
- 适用场景:未通过ABP仓储操作的实体(如直接用EF Core的
DbContext)、手动new的实体,需要补充审计字段时使用。 - 自动填充场景:若实体通过
IRepository的InsertAsync/UpdateAsync操作,框架会自动调用EntityAuditingHelper,无需手动处理(如之前的BookAppService示例)。
四、审计日志的核心配置与查看
1. 基础配置(模块中启用审计)
ABP默认启用审计,若需调整配置(如排除某些方法、设置日志保存方式),可在模块的ConfigureServices中配置:
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAuditingOptions>(options =>
{
// 全局排除审计的方法(如所有以"Internal"开头的方法)
options.IgnoredMethods.Add("Internal*");
// 审计日志保存到数据库(默认),也可配置保存到文件/第三方日志系统
options.IsEnabledForGetRequests = true; // 是否记录GET请求(默认false,避免查询日志过多)
});
}
2. 查看审计日志
审计日志默认保存到AbpAuditLogs表(EF Core),可通过IAuditLogRepository查询历史日志:
public async Task<List<AuditLogDto>> GetAuditLogsAsync(DateTime startDate)
{
var logs = await _auditLogRepo.GetListAsync(
filter: log => log.ExecutionTime >= startDate,
orderBy: log => log.ExecutionTime.Descending()
);
return ObjectMapper.Map<List<AuditLog>, List<AuditLogDto>>(logs);
}
五、总结:三类核心类的适用场景
| 类/特性 | 用法方式 | 核心优势 | 适用场景 |
|---|---|---|---|
AuditedAttribute |
声明式(特性) | 零代码、自动记录 | 常规CRUD、关键方法(如支付、审批) |
IAuditingManager |
编程式(代码) | 灵活自定义、补充业务信息 | 非标准操作、需额外备注的关键业务 |
EntityAuditingHelper |
编程式(代码) | 手动填充审计字段 | 非仓储操作的实体、手动创建的实体 |
通过这三类工具,ABP可覆盖从“自动记录”到“手动定制”的全场景审计需求,确保系统操作可追溯、数据安全有保障。
六、审计相关的类
在 ABP Framework 中,审计相关的类主要用于自动记录实体的创建、修改、删除等操作信息(如创建人、创建时间、修改人、修改时间、是否删除等),这些类通过接口和基类的形式提供,方便开发者快速实现审计功能。
| 类别 | 类 / 接口名称 | 继承 / 实现关系 | 核心审计字段 | 适用场景 |
|---|---|---|---|---|
| 领域层实体基类 | CreationAuditedEntity<TKey> |
继承 Entity<TKey>,实现 ICreationAuditedObject |
- CreationTime(创建时间)- CreatorId(创建人 ID) |
仅需记录「创建信息」的实体(无需修改 / 删除审计) |
ModificationAuditedEntity<TKey> |
继承 Entity<TKey>,实现 IModificationAuditedObject |
- LastModificationTime(最后修改时间)- LastModifierId(最后修改人 ID) |
仅需记录「修改信息」的实体(较少单独使用) | |
DeletionAuditedEntity<TKey> |
继承 Entity<TKey>,实现 IDeletionAuditedObject |
- IsDeleted(软删除标记)- DeletionTime(删除时间)- DeleterId(删除人 ID) |
仅需记录「软删除信息」的实体(通常结合其他审计字段使用) | |
AuditedEntity<TKey> |
继承 Entity<TKey>,实现 IAuditedObject(组合 ICreationAuditedObject + IModificationAuditedObject) |
包含 CreationAuditedEntity + ModificationAuditedEntity 的所有字段 |
需要记录「创建 + 修改」信息的实体 | |
FullAuditedEntity<TKey> |
继承 AuditedEntity<TKey>,实现 IFullAuditedObject(增加 IDeletionAuditedObject) |
包含 AuditedEntity + DeletionAuditedEntity 的所有字段 |
需要记录「创建 + 修改 + 软删除」全量审计的实体 | |
CreationAuditedAggregateRoot<TKey> |
继承 AggregateRoot<TKey>,实现 ICreationAuditedObject |
同 CreationAuditedEntity<TKey> |
仅需记录「创建信息」的聚合根(领域驱动设计中的根实体) | |
AuditedAggregateRoot<TKey> |
继承 AggregateRoot<TKey>,实现 IAuditedObject |
同 AuditedEntity<TKey> |
需要记录「创建 + 修改」信息的聚合根 | |
FullAuditedAggregateRoot<TKey> |
继承 AggregateRoot<TKey>,实现 IFullAuditedObject |
同 FullAuditedEntity<TKey> |
需要记录「创建 + 修改 + 软删除」全量审计的聚合根 | |
| 应用层 DTO 基类 | CreationAuditedEntityDto<TKey> |
实现 ICreationAuditedObject |
同 CreationAuditedEntity<TKey> 的字段(DTO 层) |
接口返回时需包含「创建信息」的 DTO |
AuditedEntityDto<TKey> |
实现 IAuditedObject |
同 AuditedEntity<TKey> 的字段(DTO 层) |
接口返回时需包含「创建 + 修改」信息的 DTO | |
FullAuditedEntityDto<TKey> |
继承 AuditedEntityDto<TKey>,实现 IFullAuditedObject |
同 FullAuditedEntity<TKey> 的字段(DTO 层) |
接口返回时需包含「创建 + 修改 + 软删除」全量审计信息的 DTO | |
EntityDto<TKey> |
无审计接口实现 | 仅包含 Id 字段(无审计信息) |
无需返回审计信息的基础 DTO,可按需扩展 | |
| 审计接口 | ICreationAuditedObject |
无 | - CreationTime、CreatorId |
定义「创建审计」规范,被实体 / DTO 基类实现 |
IModificationAuditedObject |
无 | - LastModificationTime、LastModifierId |
定义「修改审计」规范,被实体 / DTO 基类实现 | |
IDeletionAuditedObject |
无 | - IsDeleted、DeletionTime、DeleterId |
定义「软删除审计」规范,被实体 / DTO 基类实现 | |
IAuditedObject |
继承 ICreationAuditedObject + IModificationAuditedObject |
组合上述两类接口的字段 | 定义「创建 + 修改」审计的组合规范 | |
IFullAuditedObject |
继承 IAuditedObject + IDeletionAuditedObject |
组合上述三类接口的字段 | 定义「创建 + 修改 + 软删除」全量审计的组合规范 |
关键说明:
- 实体 vs 聚合根:
Entity是基础实体类,AggregateRoot是领域驱动设计中聚合的根节点(需满足聚合内一致性),审计基类分别为两者提供对应实现。 - 自动填充:ABP 框架通过拦截器(如
AuditInterceptor)自动为实现审计接口的实体填充字段(如创建时设CreationTime,修改时更新LastModificationTime),无需手动赋值。 - DTO 适配:DTO 基类与实体基类字段一一对应,用于接口返回时暴露审计信息,避免直接返回领域实体。

浙公网安备 33010602011771号