.Net Core 审计日志实现
前言:
近日在项目协同开发过程中出现了问题,数据出现了异常;其他人员怀疑项目数据丢失程序存在问题。于是通过排查程序提供的审计日志最终还原了当时操作及原因。
可见审计日志在排查、定位问题是相当有用的,那么在.Net Core 如何来实现审计日志呢?
接下来一步步来实现效果
一、审计日志定义及作用
审计日志:
维基百科: “审计跟踪(也叫审计日志)是与安全相关的按照时间顺序的记录,记录集或者记录源,它们提供了活动序列的文档证据,这些活动序列可以在任何时间影响一个特定的操作,步骤或其他”
作用:
1、快速定位问题耗时及性能情况
2、记录调用时环境信息:如浏览器、参数等
二、.Net Core 中实现审计日志
那么怎么实现审计日志呢?其实核心思想很简单。包含以下步骤:
- 获取调用接口方法时相关信息
- 记录当前接口耗时情况
- 保存审计日志信息到数据库中
那么如何获取调用接口时相关信息呢?.Net Core中可以使用:过滤器、拦截器 实现。
本次示例中将采用过滤器实现审计日志实现功能;主要流程如下

定义审计日志信息:
public class AuditInfo
{
/// <summary>
/// 调用参数
/// </summary>
public string Parameters { get; set; }
/// <summary>
/// 浏览器信息
/// </summary>
public string BrowserInfo { get; set; }
/// <summary>
/// 客户端信息
/// </summary>
public string ClientName { get; set; }
/// <summary>
/// 客户端IP地址
/// </summary>
public string ClientIpAddress { get; set; }
/// <summary>
/// 执行耗时
/// </summary>
public int ExecutionDuration { get; set; }
/// <summary>
/// 执行时间
/// </summary>
public DateTime ExecutionTime { get; set; }
/// <summary>
/// 返回内容
/// </summary>
public string ReturnValue { get; set; }
/// <summary>
/// 异常对象
/// </summary>
public Exception Exception { get; set; }
/// <summary>
/// 方法名
/// </summary>
public string MethodName { get; set; }
/// <summary>
/// 服务名
/// </summary>
public string ServiceName { get; set; }
/// <summary>
/// 调用者信息
/// </summary>
public string UserInfo { get; set; }
/// <summary>
/// 自定义数据
/// </summary>
public string CustomData { get; set; }
}
- 实现审计日志过滤器
using AuditLogDemo.Models;
using AuditLogDemo.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks; namespace AuditLogDemo.Fliters
{
public class AuditLogActionFilter : IAsyncActionFilter
{
/// <summary>
/// 审计日志服务对象
/// </summary>
private readonly IAuditLogService _auditLogService;
/// <summary>
/// 登录用户
/// </summary>
private readonly ISession _Session;
/// <summary>
/// 日志记录
/// </summary>
private readonly ILogger<AuditLogActionFilter> _logger; public AuditLogActionFilter(
IAuditLogService auditLogService,
ISession Session,
ILogger<AuditLogActionFilter> logger
)
{
_Session = Session;
_logger = logger;
_auditLogService = auditLogService;
} public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// 判断是否写日志
if (!ShouldSaveAudit(context))
{
await next();
return;
}
//接口Type
var type = (context.ActionDescriptor as ControllerActionDescriptor).ControllerTypeInfo.AsType();
//方法信息
var method = (context.ActionDescriptor as ControllerActionDescriptor).MethodInfo;
//方法参数
var arguments = context.ActionArguments;
//开始计时
var stopwatch = Stopwatch.StartNew();
var auditInfo = new AuditInfo
{
UserInfo = _Session?.Id,
ServiceName = type != null ? type.FullName.TruncateWithPostfix(EntityDefault.FieldsLength250) : "",
MethodName = method.Name.TruncateWithPostfix(EntityDefault.FieldsLength250),
////请求参数转Json
Parameters = JsonConvert.SerializeObject(arguments),
ExecutionTime = DateTime.Now,
BrowserInfo = context.HttpContext.Request.Headers["User-Agent"].ToString().TruncateWithPostfix(EntityDefault.FieldsLength250),
ClientIpAddress = context.HttpContext.Connection.RemoteIpAddress.ToString().TruncateWithPostfix(EntityDefault.FieldsLength50),
//ClientName = _clientInfoProvider.ComputerName.TruncateWithPostfix(EntityDefault.FieldsLength100),
Id = Guid.NewGuid().ToString()
}; ActionExecutedContext result = null;
try
{
result = await next();
if (result.Exception != null && !result.ExceptionHandled)
{
auditInfo.Exception = result.Exception;
}
}
catch (Exception ex)
{
auditInfo.Exception = ex;
throw;
}
finally
{
stopwatch.Stop();
auditInfo.ExecutionDuration = Convert.ToInt32(stopwatch.Elapsed.TotalMilliseconds); if (result != null)
{
switch (result.Result)
{
case ObjectResult objectResult:
auditInfo.ReturnValue = JsonConvert.SerializeObject(objectResult.Value);
break; case JsonResult jsonResult:
auditInfo.ReturnValue = JsonConvert.SerializeObject(jsonResult.Value);
break; case ContentResult contentResult:
auditInfo.ReturnValue = contentResult.Content;
break;
}
}
Console.WriteLine(auditInfo.ToString());
//保存审计日志
await _auditLogService.SaveAsync(auditInfo);
}
} /// <summary>
/// 是否需要记录审计
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
private bool ShouldSaveAudit(ActionExecutingContext context)
{
if (!(context.ActionDescriptor is ControllerActionDescriptor))
return false;
var methodInfo = (context.ActionDescriptor as ControllerActionDescriptor).MethodInfo; if (methodInfo == null)
{
return false;
} if (!methodInfo.IsPublic)
{
return false;
} if (methodInfo.GetCustomAttribute<AuditedAttribute>() != null)
{
return true;
} if (methodInfo.GetCustomAttribute<DisableAuditingAttribute>() != null)
{
return false;
} var classType = methodInfo.DeclaringType;
if (classType != null)
{
if (classType.GetTypeInfo().GetCustomAttribute<AuditedAttribute>() != null)
{
return true;
} if (classType.GetTypeInfo().GetCustomAttribute<AuditedAttribute>() != null)
{
return false;
}
}
return false;
}
}
}
该内容为实现审计日志功能主要逻辑,通过过滤器获取当前执行控制器、方法判断是否需要记录审计日志;其他请求参数、客户端ip等相关基本信息组成审计日志对象,并记录调用时间。
- 注册过滤器
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.Filters.Add(typeof(AuditLogActionFilter));
}); //审计日志存储
services.AddDbContext<AuditLogDBContent>(options =>
{
string conn = Configuration.GetConnectionString("LogDB");
options.UseSqlite(conn);
});
}
到此审计日志主要逻辑已经实现完成。是不是很简单
三、总结
回过头来看,在.net core 中需要统一监控或过滤时,可以采用过滤器(Filter)或拦截器来实现相关效果
.Net Core中 Filter 常件的有:Authorization Filter(认证过滤器),Resource Filter(资源过滤器),Exception Filter(异常过滤器),Action Filter(方法过滤器),Result Filter(结果过滤器)
.Net Core 审计日志实现的更多相关文章
- ABP文档 - 审计日志
文档目录 本节内容: 简介 关于 IAuditingStore 配置 通过特性启用/禁用 注意 简介 维基百科:“一个审计追踪(也叫审计日志)是一个安全相关的时序记录.记录组.和/或记录源和目标,作为 ...
- ABP官方文档翻译 4.6 审计日志
审计日志 介绍 关于IAuditingStore 配置 通过特性启用/禁用 注意事项 介绍 维基百科:“审计追踪(也称为审计日志)是与安全相关的按时间先后的记录.记录集合.记录的目的地和源,提供一系列 ...
- .NET Core的日志[5]:利用TraceSource写日志
从微软推出第一个版本的.NET Framework的时候,就在“System.Diagnostics”命名空间中提供了Debug和Trace两个类帮助我们完成针对调试和跟踪信息的日志记录.在.NET ...
- .NET Core的日志[4]:将日志写入EventLog
面向Windows的编程人员应该不会对Event Log感到陌生,以至于很多人提到日志,首先想到的就是EventLog.EventLog不仅仅记录了Windows系统自身针对各种事件的日志,我们的应用 ...
- .NET Core的日志[3]:将日志写入Debug窗口
定义在NuGet包"Microsoft.Extensions.Logging.Debug"中的DebugLogger会直接调用Debug的WriteLine方法来写入分发给它的日志 ...
- .NET Core的日志[2]:将日志输出到控制台
对于一个控制台应用,比如采用控制台应用作为宿主的ASP.NET Core应用,我们可以将记录的日志直接输出到控制台上.针对控制台的Logger是一个类型为ConsoleLogger的对象,Consol ...
- .NET Core的日志[1]:采用统一的模式记录日志
记录各种级别的日志是所有应用不可或缺的功能.关于日志记录的实现,我们有太多第三方框架可供选择,比如Log4Net.NLog.Loggr和Serilog 等,当然我们还可以选择微软原生的诊断框架(相关A ...
- ABP(现代ASP.NET样板开发框架)系列之19、ABP应用层——审计日志
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之19.ABP应用层——审计日志 ABP是“ASP.NET Boilerplate Project (ASP.NET ...
- ABP理论学习之审计日志
返回总目录 本篇目录 介绍 配置 通过特性开启/关闭 注意 我项目中的例子 介绍 维基百科说: "审计跟踪(也叫审计日志)是与安全相关的按照时间顺序的记录,记录集或者记录源,它们提供了活动序 ...
随机推荐
- 「刷题笔记」哈希,kmp,trie
Bovine Genomics 暴力 str hash+dp 设\(dp[i][j]\)为前\(i\)组匹配到第\(j\)位的方案数,则转移方程 \[dp[i][j+l]+=dp[i-1][j] \] ...
- NodeJS+formidable实现文件上传加自动重命名
前述 本人node初学者,此前使用原生node实现文件上传时遇到了一些困难,只做到了.txt 和.png两中格式的文件可以正常上传,如果上传其他格式文件服务端保存的文件会无法正常打开,原因是对form ...
- xargs--冬天里的一丝暖意
本文为博客园作者所写: 一寸HUI,个人博客地址:https://www.cnblogs.com/zsql/ 你有批量kill作业吗?有因为删除文件夹的内容太多而报错吗?-bash: /bin/rm: ...
- 分享篇:聊一聊 15.5K 的 FileSaver,是如何工作的?
聊一聊 15.5K 的 FileSaver,是如何工作的? FileSaver.js 是在客户端保存文件的解决方案,非常适合在客户端上生成文件的 Web 应用程序.它简单易用且兼容大多数浏览器,被作为 ...
- npm常用操作
Npm常用操作 1. 淘宝镜像 1.1 npm临时使用淘宝镜像安装依赖包 npm i -g express --registry https://registry.npm.taobao.org 1.2 ...
- Python MoviePy中文教程导览及可执行音视频剪辑工具下载
☞ ░ 前往老猿Python博文目录 ░ <Python音视频剪辑库MoviePy1.0.3中文教程导览及可执行工具下载>是老猿两个关于moviepy的专栏<PyQt+moviepy ...
- PyQt学习随笔:QTableWidget水平表头horizontalHeader、竖直表头verticalHeader的相关操作方法
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTableWidget表格部件的表头包括水平表头和竖直表头,水平表头每节对应表格的一列,竖直表头对 ...
- PyQt(Python+Qt)学习随笔:QTableWidget表格部件中行高和列宽的计算方式
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 QTableWidget表格部件中行高和列宽的计算在Qt提供的资料中内容介绍比较泛,细节说得不清楚, ...
- CentOS下安装SublimeText
1.Install the GPG key: sudo rpm -v --import https://download.sublimetext.com/sublimehq-rpm-pub.gpg 2 ...
- SSH无密码登陆
http://blog.chinaunix.net/uid-26284395-id-2949145.html