检测是否手动调用AuthorizationAttribute

时间:2016-06-03 15:31:33

标签: c# asp.net-mvc-5 custom-attributes authorize-attribute

我在旧版MVC5项目中有自定义AuthorizeAttribute

public class AuthorizeWithLoggingAttribute : AuthorizeAttribute
{
     public override void OnAuthorization(AuthorizationContext filterContext)
     {
         if (!base.AuthorizeCore(httpContext)) {Log(FilterContext);}
     }
 }

我们在查看日志时注意到,除了要应用于[AuthorizeWithLogging]的控制器之外,还在代码中的其他位置显式调用它,生成虚假日志:

var filters = new FilterInfo(FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor));
foreach (var authFilter in filters.AuthorizationFilters)
{
    authFilter.OnAuthorization(authContext);
    if (authContext.Result != null) {return false;}
}

有没有办法告诉(通过StackTrace或者什么)OnAuthorization方法是显式调用还是从属性调用?我目前最好的是 Environment.StackTrace.Contains("at System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters")

2 个答案:

答案 0 :(得分:1)

您可以使用的一条路线是StackFrame。这比你现在的要干净一些。更多详情可在这找到: How can I find the method that called the current method

答案 1 :(得分:1)

AuthorizeAttribute只有一个责任:确定用户是否获得授权。由于各种原因,这可以在应用程序的多个位置使用。

由于未经授权而采取的任何操作(例如返回HTTP 401响应)都被委托给设置为ActionResult属性的AuthorizationContext.Result类型的处理程序。例如,以下是AuthorizeAttribute.HandleUnauthorizedRequest的默认实现:

protected virtual void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
    // Returns HTTP 401 - see comment in HttpUnauthorizedResult.cs.
    filterContext.Result = new HttpUnauthorizedResult();
}

如果您在未授权用户时尝试进行审核,则应将审核放入ActionResult处理程序,而不是自定义AuthorizeAttribute。这样可以确保仅在执行ActionResult时(即当前页面未经授权时)执行审计,而不是在每种情况下都检查授权。

public class AuthorizeWithLoggingAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        filterContext.Result = new LoggingActionResult(new HttpUnauthorizedResult(), filterContext);
    }
}

public class LoggingActionResult : ActionResult
{
    private readonly ActionResult innerActionResult;
    private readonly AuthorizationContext filterContext;

    public LoggingActionResult(ActionResult innerActionResult, AuthorizationContext filterContext)
    {
        if (innerActionResult == null)
            throw new ArgumentNullException("innerActionResult");
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");

        this.innerActionResult = innerActionResult;
        this.filterContext = filterContext;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        // Do logging (or apparently you want auditing) here
        Log(this.filterContext);

        innerActionResult.ExecuteResult(context);
    }
}
  

注意:我会将它们命名为AuthorizeWithAuditingAttributeAuditingActionResult,因为您显然需要审核,而不是在这种情况下登录。