ASP.NET MVC - 使用ActionFilterAttribute验证POST数据

5

实际上,我有一个应用程序,它使用Web服务来检索一些客户信息。 因此,我在我的ActionResult中验证登录信息,例如:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult ClientLogin(FormCollection collection)
{
    if(Client.validate(collection["username"], collection["password"]))
    {
        Session["username"] = collection["username"];
        Session["password"] = collection["password"];
        return View("valid");
    }
    else
    {
       Session["username"] = "";
       Session["password"] = "";
       return View("invalid");
    }
}

客户端验证(Client.Validate())是一种基于POST用户名和密码提供的信息返回布尔值的方法。

但是我改变了主意,我想在方法开头使用那个漂亮的ActionFilterAttributes,所以它只会在Client.validate()返回true时呈现,与[Authorize]相同,但使用我的自定义Web服务。所以我会得到这样的东西:

[AcceptVerbs(HttpVerbs.Post)]
[ValidateAsClient(username=postedUsername,password=postedPassword)]
//Pass Posted username and password to ValidateAsClient Class
//If returns true render the view
public ActionResult ClientLogin()
{
    return View('valid')
}

然后在ValidateAsClient函数内部,我会有类似以下的代码:

public class ValidateAsClient : ActionFilterAttribute
{
    public string username { get; set; }
    public string password { get; set; }

    public Boolean ValidateAsClient()
    {
        return Client.validate(username,password);
    }
}

我的问题是,我不知道如何使它正常工作,因为我不知道如何将POSTED信息传递给[ValidateAsClient(username=postedUsername,password=postedPassword)],而且,我该如何使函数ValidateAsClient正常工作?

希望这很容易理解 提前感谢。

4个回答

7
可能是这样的:

类似于这样:

[AttributeUsage(AttributeTargets.All)]
public sealed class ValidateAsClientAttribute : ActionFilterAttribute
{
    private readonly NameValueCollection formData;
    public NameValueCollection FormData{ get { return formData; } }

    public ValidateAsClientAttribute (NameValueCollection formData)
    {
        this.formData = formData;
    }

    public override void OnActionExecuting
               (ActionExecutingContext filterContext)
    {
        string username = formData["username"];
        if (string.IsNullOrEmpty(username))
        {
             filterContext.Controller.ViewData.ModelState.AddModelError("username");
        }
        // you get the idea
    }
}

并且像这样使用:

[ValidateAsClient(HttpContext.Request.Form)]

10
我认为你可以通过 filterContext.HttpContext.Request.Form 访问表单集合,而不是传递它。 - Çağdaş Tekin
谢谢你的回答,HeavyWave,非常好。还有一个问题:在这种情况下使用ActionExecutingContext和ActionExecutedContext是否有区别? - zanona
ActionExecutedContext 应该在 OnActionExecuted 方法中使用,该方法在控制器的操作方法之后执行。因此,在 ActionExecutedContext 中,您可以访问执行结果的一些内容。只需使用 IntelliSense 玩弄它即可。 - Egor Pavlikhin

6

您需要重写以下方法。

public override void OnActionExecuting(ActionExecutingContext context)

通过上下文对象,访问您的帖子数据。


检查ActionExecutingContext.RequestContext.HttpContext.Request.Form,你应该能够在那里获取POST值。 - J.W.

3
我认为在这种情况下使用ActionFilterAttribute并不是一个好主意。而你想做的事情绝对不同于Authorize属性所做的事情。 Authorize属性只是将一个通用逻辑注入到控制器/操作中。它的作用是:

如果用户未登录,则重定向到登录页面,否则让操作继续执行。

你的ClientLogin操作目前已经做到了应该做的事情。将该逻辑转移到ActionFilterAttribute中会导致设计不良。

你说得对,将本应只由一个操作使用的东西变成属性并不是一个好主意。Authorize 表示该操作需要用户授权,它不包含任何逻辑。 - Egor Pavlikhin
是的,我理解你的观点,实际上问题在于我需要客户端在整个应用中执行几个不同的操作,这将要求客户端登录,否则它将被重定向到登录页面。所以我在想,可能会更简单和美观(因为我现在是ASP.NET的入门者,对任何错误的应用感到抱歉),在每个方法的开头加上[ValidateAsClient]。但我不确定这是否正确,感谢你的建议。 - zanona
好的,按照你的方式做不会出问题。 :) 只是使用属性的方式并不完全自然。就这样。 - Çağdaş Tekin

2
我会使用ASP.NET MVC中的自定义绑定器来解决这个问题。
假设您的操作将具有以下签名。
public ActionResult MyAction(MyParameter param)
{
  if(param.isValid)
    return View("valid");
  else
    return View("invalid");
}

MyParam类:

    public class MyParameter
    {
      public string UserName{get;set;}
      public string Password {get;set;}

      public bool isValid
      {
        //check if password and username is valid.
      }

}

然后是自定义绑定器。
public class CustomBinder:IModelBinder
{
 public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
           var p = new MyParam();
           // extract necessary data from the bindingcontext like
           p.UserName = bindingContext.ValueProvider["username"] != null
                        ? bindingContext.ValueProvider["username"].AttemptedValue
                        : "";
          //initialize other attributes.
        }
}

这是一个简单任务的过度设计。@HeavyWave提供了一个优秀而简单的解决方案。 - reflog
Tss...我只是不知道其他的做法 :)。 - Eugeniu Torica

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