通过研究我正在使用ASP.NET MVC2构建的系统的安全性,我发现了ASP.NET的请求验证特性--这确实是一个非常简洁的特性。但很明显,当用户使用HTML输入数据时,我不想让他们看到黄屏死亡,所以我想找到一个更好的解决方案。
我的想法是找到所有包含无效数据的字段,并在调用操作之前将它们添加到ModelStateDictionary中,以便它们在UI中自动显示为错误消息。在谷歌了一下之后,似乎还没有人实现过这一点,这让我感到困惑,因为它看起来如此明显。这里有没有人有关于如何做到这一点的建议?我自己的想法是向控制器提供一个自定义的ControllerActionInvoker,如here所描述的,它以某种方式检查并修改ModelStateDictionary,但我被困在如何做最后一点。
仅仅捕获HttpRequestValidationException异常似乎不是一种有用的方法,因为它实际上并不包含我需要的所有信息。
我自己已经回答了这个问题,但我仍然非常有兴趣听到任何更优雅/健壮的解决方案。
发布于 2010-06-02 14:59:27
在研究了MVC如何进行模型绑定之后,我自己想出了一个解决方案。我用一个覆盖Execute方法的自定义实现扩展了Controller类,如下所示:
public abstract class ExtendedController : Controller
{
protected override void Execute(RequestContext requestContext)
{
ActionInvoker = new ExtendedActionInvoker(ModelState);
ValidateRequest = false;
base.Execute(requestContext);
}
}为了控制何时进行请求验证,我在web.config中添加了以下内容
<httpRuntime requestValidationMode="2.0"/>操作的核心发生在ControllerActionInvoker类的自定义实现中:
public class ExtendedActionInvoker : ControllerActionInvoker
{
private ModelStateDictionary _modelState;
private const string _requestValidationErrorKey = "RequestValidationError";
public ExtendedActionInvoker(ModelStateDictionary modelState)
{
_modelState = modelState;
}
protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
{
var action = base.FindAction(controllerContext, controllerDescriptor, actionName);
controllerContext.RequestContext.HttpContext.Request.ValidateInput();
return action;
}
protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
{
try
{
return base.GetParameterValue(controllerContext, parameterDescriptor);
}
catch (HttpRequestValidationException)
{
var fieldName = parameterDescriptor.ParameterName;
_modelState.AddModelError(fieldName, ModelRes.Shared.ValidationRequestErrorMessage);
_modelState.AddModelError(_requestValidationErrorKey, ModelRes.Shared.ValidationRequestErrorMessage);
var parameterType = parameterDescriptor.ParameterType;
if (parameterType.IsPrimitive || parameterType == typeof(string))
{
return GetValueFromInput(parameterDescriptor.ParameterName, parameterType, controllerContext);
}
var complexActionParameter = Activator.CreateInstance(parameterType);
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(complexActionParameter))
{
object propertyValue = GetValueFromInput(descriptor.Name, descriptor.PropertyType, controllerContext);
if (propertyValue != null)
{
descriptor.SetValue(complexActionParameter, propertyValue);
}
}
return complexActionParameter;
}
}
private object GetValueFromInput(string parameterName, Type parameterType, ControllerContext controllerContext)
{
object propertyValue;
controllerContext.RouteData.Values.TryGetValue(parameterName, out propertyValue);
if (propertyValue == null)
{
propertyValue = controllerContext.HttpContext.Request.Params[parameterName];
}
if (propertyValue == null)
return null;
else
return TypeDescriptor.GetConverter(parameterType).ConvertFrom(propertyValue);
}
}这样做的目的是在找到操作之后执行请求验证。如果请求无效,这不会立即导致错误,但当调用GetParameterValue时,它将抛出异常。为了避免这种情况,我覆盖了此方法,并将基调用try-catch包装起来。如果捕获到异常,我基本上会重新实现模型绑定(我对此代码的质量没有任何保证),并为值向ModelStateDictionary对象添加一个错误。
另外,由于我希望以标准格式为我的ajax方法返回一个错误,因此我还添加了一个定制的InvokeActionMethod实现。
protected override ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
{
if (_modelState.ContainsKey(_requestValidationErrorKey))
{
var errorResult = new ErrorResult(_modelState[_requestValidationErrorKey].Errors[0].ErrorMessage, _modelState);
var type = controllerContext.Controller.GetType();
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
if (methods.Where(m => m.Name == actionDescriptor.ActionName).First().ReturnType == typeof(JsonResult))
return (controllerContext.Controller as ExtendedControllerBase).GetJson(errorResult);
}
return base.InvokeActionMethod(controllerContext, actionDescriptor, parameters);
}https://stackoverflow.com/questions/2864935
复制相似问题