设为首页 加入收藏

TOP

[Abp vNext 源码分析] - 8. 审计日志(二)
2019-10-09 20:03:45 】 浏览:175
Tags:Abp vNext 源码 分析 审计 日志
tLogScope = _auditingManager.Current; if (auditLogScope == null) { return false; } // 进行二次判断是否需要存储审计日志。 if (!_auditingHelper.ShouldSaveAudit(invocation.Method)) { return false; } // 构建审计日志信息。 auditLog = auditLogScope.Log; auditLogAction = _auditingHelper.CreateAuditLogAction( auditLog, invocation.TargetObject.GetType(), invocation.Method, invocation.Arguments ); return true; }

2.2 审计日志的持久化

大体流程和我们上面说的一样,不过好像缺少了重要的一步,那就是 持久化操作。你可以在 Volo.Abp.Auditing 模块发现有 IAuditingStore 接口的定义,但是它的 SaveAsync() 方法却没有在拦截器内部被调用。同样在 MVC 的审计日志过滤器实现,你也会发现没有调用持久化方法。

那么我们的审计日志是在什么时候被持久化的呢?找到 SaveAsync() 被调用的地方,发现 ABP vNext 实现了一个审计日志的 ASP.NET Core 中间件。

在这个中间件内部的实现比较简单,首先通过一个判定方法,决定是否为本次请求执行 IAuditingManager.BeginScope() 方法。如果判定通过,则执行,否则不仅行任何操作。

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();
        }
    }
}

可以看到,在这里 ABP vNext 使用 IAuditingManager 构建,调用其 BeginScope() 构建了一个 IAuditLogSaveHandle 对象,并使用其提供的 SaveAsync() 方法进行持久化操作。

2.2.1 嵌套的持久化操作

在构造出来的 IAuditLogSaveHandle 对象里面,还是使用的 IAuditingManager 的默认实现 AuditingManager 所提供的 SaveAsync() 方法进行持久化

阅读源码之后,发现了下面两个问题:

  1. IAuditingManager 没有将持久化方法公开 出来,而是作为一个 protected 级别的方法。
  2. 为什么还要借助 IAuditLogSaveHandle 间接地调用 管理器的持久化方法。

这就要从中间件的代码说起了,可以看到它是构造出了一个可以被释放的 IAuditLogSaveHandle 对象。ABP vNext 这样做的目的,就是可以嵌套多个 Scope,即 只在某个范围内 才将审计日志记录下来。这种特性类似于 工作单元 的用法,其底层实现是 之前文章 讲过的 IAmbientScopeProvider 对象。

例如在某个应用服务内部,我可以这样写代码:

using (var scope = _auditingManager.BeginScope())
{
    await myAuditedObject1.DoItAsync(new InputObject { Value1 = "我是内部嵌套测试方法1。", Value2 = 5000 });
    using (var scope2 = _auditingManager.BeginScope())
    {
        await myAuditedObject1.DoItAsync(new InputObject {Value1 = "我是内部嵌套测试方法2。", Value2 = 10000});
        await scope2.SaveAsync();
    }
    await scope.SaveAsync();
}

想一下之前的代码,在拦截器内部,我们是通过 IAuditingManager.Current 拿到当前可用的 IAuditLogScope ,而这个 Scope 就是在调用 IAuditingManager.BeginScope() 之后生成的

2.2.3 最终的持久化代码

通过上述的流程,我们得知最后的审计日志信息会通过 IAuditingStore 进行持久化。ABP vNext 为我们提供了一个默认的 SimpleLogAuditingStore 实现,其内部就是调用 ILogger 将信息输出。如果需要将审计日志持久化到数据库,你可以实现 IAUditingStore 接口,覆盖原有实现 ,或者使用 ABP vNext 提供的 Volo.Abp.AuditLogging 模块。

2.3 审计日志的序列化

审计日志的序列化处理是在 IAuditingHelper 的默认实现内部被使用,可以看到构建审计日志的方法内部,通过自定义的序列化器来将 Action 的参数进行序列化处理,方便存储。

public virtual AuditLogActionInfo CreateAuditLogAction(
    AuditLogInfo auditLog,
    Type type, 
    MethodInfo method, 
    IDictionary<string, object> arguments)
{
    var actionInfo = new AuditLogActionInfo
    {
        ServiceName = type != null
            ? type.FullName
            : "",
        MethodName = method.Name,
        // 序列化参数信息。
        Parameters = SerializeConvertArguments(arguments),
        ExecutionTime = Clock.Now
    };

    //TODO Execute contributors

    return actionInfo;
}

protected virtual string SerializeConvertArguments(IDictionary<string, object> arguments)
{
    try
    {
        if (arguments.IsNullOrEmpty())
        {
            return "{}";
        }

        var dictionary = new Dictionary<string, object>();

        foreach (var argument in arguments)
        {
            // 忽略的代码,主要作用是构建参数字典。
        }

        // 调用序列化器,序列化 Action 的调用参数。
        return AuditSerializer.Serialize(dictionary);
    }
    catch (Exception ex)
    {
        Logger.LogException(ex
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇.net core 3.0 Signalr - 04 使用.. 下一篇关于部署版本遇到的---警告: 程序..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目