跳到主要内容
版本:3.0.0

安全审计(Aegis.Security.Audit)

Aegis.Security.Audit 用来记录业务操作留痕。它负责注册 AuditLogger<T> 和默认审计存储,让业务服务或控制器可以用链式写法记录谁做了什么、影响了什么资源、变更了什么数据。

组件概览

字段说明
组件名称安全审计
真实类库Aegis.Security.Audit
组件定位操作留痕与审计日志组件
引入方式安装 NuGet,并在 Component.deps.jsonServices 中启用 Security.Audit
组件声明Security.Audit
核心能力AuditLogger<T>、链式审计构建器、IAuditStorage
默认存储AuditConsoleStorage

什么时候要用它

适合场景:

  • 需要记录敏感操作、关键业务操作
  • 需要做合规审计和问题追溯
  • 需要保留“谁在什么时间改了什么”的证据链

最小可运行路径

第一步:启用 Security.Audit

{
"Components": {
"Services": [
"Security.Audit"
],
"Middlewares": []
}
}

第二步:注入 AuditLogger<T>

public class SettlementService
{
private readonly AuditLogger<SettlementService> _auditLogger;

public SettlementService(AuditLogger<SettlementService> auditLogger)
{
_auditLogger = auditLogger;
}
}

第三步:直接写审计日志

await _auditLogger
.SetOperator("1", OperatorType.医生, "张三")
.SetDomain(Domain.结算单)
.SetContent(OperationType.创建, "SETTLE_001", "创建结算单", "创建结算单 SETTLE_001")
.LogAsync();

默认帮你注册了什么

启用组件后,框架会默认注册:

  • AuditLogger<T>Scoped
  • IAuditStorage:默认是控制台存储

这意味着当前最小接入可以先跑起来,但正式项目通常还需要替换默认存储。

正式项目最常见的扩展点

替换默认存储

如果你希望把审计数据写入数据库、消息队列或其他介质,可以实现 IAuditStorage

public class AuditDatabaseStorage : IAuditStorage
{
private readonly IFreeSql<AegisDb> _freeSql;

public AuditDatabaseStorage(IFreeSql<AegisDb> freeSql)
{
_freeSql = freeSql;
}

public void Create(AuditRecord auditRecord)
{
_freeSql.Insert(auditRecord).ExecuteAffrows();
}

public Task CreateAsync(AuditRecord auditRecord)
{
return _freeSql.Insert(auditRecord).ExecuteAffrowsAsync();
}
}

在项目里覆盖注册

services.AddScoped<IAuditStorage, AuditDatabaseStorage>();

最常见的三种记录方式

普通操作记录

await _auditLogger
.SetOperator("1", OperatorType.医生, "张三")
.SetDomain(Domain.结算单)
.SetContent(OperationType.创建, "创建结算单", "创建结算单 SETTLE_001")
.LogAsync();

带资源标识的记录

await _auditLogger
.SetOperator("1", OperatorType.医生, "张三")
.SetDomain(Domain.结算单)
.SetContent(OperationType.更新, "SETTLE_001", "更新结算单", "修改结算单金额")
.LogAsync();

带数据变更的记录

await _auditLogger
.SetOperator("1", OperatorType.医生, "张三")
.SetDomain(Domain.结算单)
.SetContent(OperationType.更新, "SETTLE_001", "更新结算单", "修改结算单金额")
.SetChangeData("金额,状态", newData, oldData)
.LogAsync();

PreSetOperator 什么时候用

如果一个服务里的审计操作者几乎总是“当前登录用户”,可以先预设操作者,再在各个方法里直接写领域和内容。

public class SettlementService
{
private readonly AuditLogger<SettlementService> _auditLogger;

public SettlementService(AuditLogger<SettlementService> auditLogger)
{
_auditLogger = auditLogger;
_auditLogger.PreSetOperator("1", OperatorType.医生, "张三");
}

public async Task CreateAsync()
{
await _auditLogger
.SetDomain(Domain.结算单)
.SetContent(OperationType.创建, "SETTLE_001", "创建结算单", "创建结算单 SETTLE_001")
.LogAsync();
}
}

接入后怎么确认已经生效

可以这样确认:

  • 业务类里可以正常注入 AuditLogger<T>
  • 调用 Log()LogAsync() 后没有构建异常
  • 默认控制台能看到输出,或者自定义存储能拿到记录

常见问题

为什么 SetDomain(...) 直接报错

通常是因为你走的是预设操作者模式,但没有先调用 PreSetOperator(...)

正式项目能不能直接用默认存储

不建议。
默认控制台存储更适合本地调试,正式环境应替换成可持久化的存储实现。

审计应该写在 Controller 还是 Service

更推荐写在 Service。
这样更容易围绕业务动作统一记录,也更方便长期维护。

UMetaOS 审计扩展

Aegis.UMeta.Audit 是当前组件的 UMetaOS 平台存储扩展。启用后,AuditLogger<T> 产生的审计记录会自动转发到 UMetaOS 的 OTel 审计通道,而不是输出到控制台。

如何引入

NuGet 包Aegis.UMeta.Audit

Component.deps.json 中同时声明 Security.AuditUMeta.Audit

{
"Components": {
"Services": [
"Security.Audit",
"UMeta.Audit"
],
"Middlewares": [
"UMeta.Audit"
]
}
}

前置条件:需要先启用 UMeta.Logging 组件来初始化 OTel SDK,否则审计通道不可用。

使用方式

启用后,业务代码不需要任何改动。仍然注入 AuditLogger<T>,调用方式完全一致:

await _auditLogger
.SetOperator("1", OpEnum.医生, "张三")
.SetDomain(Domain.结算单)
.SetContent(OperationType.创建, "1", "创建结算单", "创建结算单xxxx")
.LogAsync();

区别仅在于底层存储从控制台变成了 UMetaOS 审计通道。UMetaAuditStorage 会自动将 AuditRecord 的字段映射到 OTel SDK 的审计格式,并附加当前请求的 TraceId 和 SpanId。

配套阅读