ASP.NET MVC和Web API中实现审计跟踪的正确方式是什么?

5

我正在尝试寻找一种更清晰的方法来为一个包含数百个 ControllerApiController 的已有 asp.net MVC 和 Web Api 项目添加审计跟踪功能。

审计跟踪日志应如下所示。基本上,我只想在此函数中记录 何时谁做了什么

UserID

ActionTime

Controller 

Action

我有什么遗漏的吗?如果有,请纠正我。谢谢。

目前,我发现有些方法可以实现它。

  1. 实现一个 ActionFilterAttribute 并在 OnActionExecuting 中编写自己的日志函数,然后使用此属性装饰所有操作。

  2. 为所有已有的控制器实现一个基础 Controller,例如 BaseController,并在其中编写日志记录于 OnActionExecuting。然后将所有的控制器更改为继承自 BaseController。(如果不正确,请纠正我。谢谢。)

  3. 对于 ApiController,实现一个 DelegatingHandler 来实现它。

对于 1 和 2,我需要修改所有现有的代码来实现它,例如更改基类或使用新的属性进行装饰。考虑到我的情况,这将是一项艰巨的工作,因为需要修改成千上万个类或方法。我认为这有点啰嗦。因此,我想知道是否有像 3 这样简洁的方法可以为 ApiController 实现它。谢谢。


有没有像DelegatingHandler这样的东西在MVC控制器中?这样我就不需要更改现有代码。抱歉,我是个懒人..谢谢。 - Joe.wang
我知道你提到的方法是一个好的解决办法。但是我只是想找出更好或者更懒的方式。谢谢。 - Joe.wang
1
这两个库都实现了操作过滤器,以为NET Core和NET 4.5的WebAPI和MVC生成审计跟踪。您可以在Audit.MVCAudit.WebApi上查看代码。 - thepirat000
1
这是一个非常好的库。它们运行得非常顺利。感谢您的帮助。 - Joe.wang
显示剩余2条评论
2个回答

11

我发现使用全局操作过滤器是处理诸如此类的横切/面向方面问题的最佳方法。

请注意,此代码未经过测试。

public class AuditFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var userName = HttpContext.Current.User.Identity.Name;
        var time = DateTime.Now.ToString(CultureInfo.InvariantCulture);
        var controllerName = actionContext.ControllerContext.ControllerDescriptor.ControllerName;
        var actionName = actionContext.ActionDescriptor.ActionName

        Logger.Log(string.Format("user: {0}, date: {1}, controller {2}, action {3}", userName, time, controllerName, actionName));
    }
}

在您的应用程序启动管道中的某个地方,全局注册该过滤器:

GlobalConfiguration.Configuration.Filters.Add(new AuditFilter());

这是在MVC中拦截的最简单方法。谢谢你,伙计。 - Joe.wang
实际上这是针对Web API的。您需要为MVC创建一个单独的API,它看起来基本相同,除了您将从RouteData获取控制器和操作名称,并使用GlobalFilters.Filters.Add(...)注册过滤器。 - Ronald Rogers
我理解这个解决方案可以帮助记录请求的部分。假设我想将其扩展到在实际控制器方法执行后也捕获成功/失败并记录相同的内容 - 有什么建议吗? - Kunal

2
你是否正在使用依赖注入容器?如果是或者想要使用依赖注入容器,那么它可以拦截所有对控制器的请求。这样,即使只是简单的更改,也不需要在数百个控制器中更改代码。
这里介绍Castle Windsor DI。
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;

public WindsorControllerFactory(IKernel kernel)
{
    _kernel = kernel;
}

public override void ReleaseController(IController controller)
{
    _kernel.ReleaseComponent(controller);
}

protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
    if (controllerType == null)
    {
        throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
    }

    return (IController)_kernel.Resolve(controllerType);
}
}

如果您打算使用它,可以查看此网站上的示例。我相信有一种方法可以同时在Web API和MVC控制器中使用它。


+1,是的。这是一个很好的想法。我已经在我的项目中使用了 Unity。但是...所有的控制器都没有在运行时从工厂创建。我担心拦截器可能无法正常工作...我需要进行一些研究。谢谢。 - Joe.wang
我担心另一个问题,即使用Unity拦截会丢失MVC控制器和WebApiController的上下文。我的意思是,像路由数据、请求和响应等信息不容易检索,对吗? - Joe.wang
这个能帮到你吗?https://dev59.com/sHjZa4cB1Zd3GeqPiMk5 - Mukus
需要更多时间来阅读。但这应该是一种有效的审计MVC和WebApi的方式。谢谢。 - Joe.wang

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接