检测是否手动调用了 AuthorizationAttribute
Detecting if AuthorizationAttribute manually called
我在遗留 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")
.
您可以选择的一条路线是使用 StackFrame。这会比你目前拥有的更干净一些。更多详情可在这找到:
How can I find the method that called the current method
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);
}
}
NOTE: I would name them AuthorizeWithAuditingAttribute
and AuditingActionResult
since you clearly want auditing, not logging in this case.
我在遗留 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")
.
您可以选择的一条路线是使用 StackFrame。这会比你目前拥有的更干净一些。更多详情可在这找到: How can I find the method that called the current method
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);
}
}
NOTE: I would name them
AuthorizeWithAuditingAttribute
andAuditingActionResult
since you clearly want auditing, not logging in this case.