我正在尝试将一些安全性/验证日志记录添加到我正在处理的ASP.NET MVC 3应用程序中。我想做的是使用类似于此的Action过滤器来装饰我的一些Action方法:
public class RegexValidateAttribute : ActionFilterAttribute
{
private static readonly ILog logger =
LogManager.GetLogger( typeof( RegexValidateAttribute ).FullName );
public string ParameterName { get; set; }
public string Expression { get; set; }
public override void OnActionExecuting( ActionExecutingContext filterContext )
{
string parameterValue = Convert.ToString(
filterContext.ActionParameters[ ParameterName ] );
if ( parameterValue != null )
{
if ( !Regex.IsMatch( parameterValue, Expression ) )
{
logger.Error( "INPUT_VALIDATION_EXCEPTION [ Parameter "
+ ParameterName + " did not match the regex: '"
+ parameterValue + "' :: '" + Expression + "']" );
}
}
}
}
我的控制器的定义与此相似:
public class MyController : Controller
{
[RegexValidate( ParameterName = "id", Expression = @"^\d+$" )]
public PartialViewResult MyMethod( int id = 0 )
{
<Action Proccessing>
}
}
我遇到的“问题”是因为action方法的输入参数定义为int
,如果有人传入非数字值,则参数值在此过程中更改为0确定选择哪种动作方法。当然,这是在我的ActionFilter有机会执行之前发生的,因此我没有机会记录原始的无效值。
我知道这可以通过更改要定义为string
的参数来解决,但这需要我重新编写大量代码,然后将转换逻辑添加到action方法以进行转换字符串到int。
那么,有没有办法在ActionFilter中获取原始值而不是修改后的值,或者在修改值之前执行ActionFilter?
更新: 根据@ Darin关于使用AuthorizationFilter的建议,我能够使用类似于以下内容的代码实现我的目标:
public class RegexValidateAttribute : AuthorizeAttribute
{
private static readonly ILog logger =
LogManager.GetLogger( typeof( RegexValidateAttribute ).FullName );
public string ParameterName { get; set; }
public string Expression { get; set; }
public string ReplacementValue { get; set; }
public override void OnAuthorization( AuthorizationContext filterContext )
{
string parameterValue = Convert.ToString(
filterContext.RouteData.Values[ ParameterName ] );
if ( parameterValue != null )
{
if ( !Regex.IsMatch( parameterValue, Expression ) )
{
logger.Error( "INPUT_VALIDATION_EXCEPTION [ Parameter "
+ ParameterName + " did not match the regex: '"
+ parameterValue + "' :: '" + Expression + "']" );
filterContext.RouteData.Values[ ParameterName ] = ReplacementValue;
}
}
}
}
答案 0 :(得分:5)
当您从ActionFilterAttribute派生时,模型绑定器会在 OnActionExecuting
方法之前运行。当模型绑定器运行时,它会崩溃。如果您希望方法在模型绑定器之前运行,则应实现IAuthorizationFilter
接口或派生自已实现该接口的AuthorizeAttribute
。
另一种可能性是为路由添加约束,以便在id不是数字时不调用控制器操作:
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { id = @"^\d+$" }
);