为相同的操作MVC5设置ValidateAntiForgeryToken属性为GET / POST

时间:2016-01-29 13:15:33

标签: c# asp.net-mvc-5 antiforgerytoken

我的问题很直接......

我有Action同时接受HttpGetHttpPost,但我想在http请求为ValidateAntiForgeryToken时将POST属性设置为操作,不适用于HttpGet

我可以在操作中找到请求是GET还是POST,但我需要在调用操作之前知道。

    [ValidateAntiForgeryToken]  // Only for HttpPost
    public ActionResult Index() // Allows HttpPost / HttpGet
    {

    }

有没有可能在没有重复行动的情况下实现这一目标?

谢谢

4 个答案:

答案 0 :(得分:6)

您可以有条件地检查请求的HTTP方法并自行手动执行验证:

if (Request.Method.ToLower() == "post") 
{
    System.Web.Helpers.AntiForgery.Validate();
}

答案 1 :(得分:2)

首先,这是一个非常糟糕的设计。 MVC的要点是分离控制器中的方法。如果你想让两种方法具有相同的行为,我建议你修改你的控制器,使其具有一个GET和一个POST,每个都在控制器的其他地方调用相同的方法。

但是你可以写一个Validation属性来完成你想要的东西。

根据此source code,您可以将验证属性中的OnAuthorization方法编辑为:

public void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request.HttpMethod;
        if (request != "GET")
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            ValidateAction();
        }
    }

现在检查请求是否为GET,在这种情况下它会跳过验证。完整的Attribute类是:

using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Web.Helpers;

namespace System.Web.Mvc
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class ValidateAntiForgeryTokenAttribute2 : FilterAttribute, IAuthorizationFilter
{
    private string _salt;

    public ValidateAntiForgeryTokenAttribute2()
        : this(AntiForgery.Validate)
    {
    }

    internal ValidateAntiForgeryTokenAttribute2(Action validateAction)
    {
        Debug.Assert(validateAction != null);
        ValidateAction = validateAction;
    }

    [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "AdditionalDataProvider", Justification = "API name.")]
    [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "AntiForgeryConfig", Justification = "API name.")]
    [Obsolete("The 'Salt' property is deprecated. To specify custom data to be embedded within the token, use the static AntiForgeryConfig.AdditionalDataProvider property.", error: true)]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public string Salt
    {
        get { return _salt; }
        set
        {
            if (!String.IsNullOrEmpty(value))
            {
                throw new NotSupportedException("The 'Salt' property is deprecated. To specify custom data to be embedded within the token, use the static AntiForgeryConfig.AdditionalDataProvider property.");
            }
            _salt = value;
        }
    }

    internal Action ValidateAction { get; private set; }

    public void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request.HttpMethod;
        if (request != "GET")
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            ValidateAction();
        }
    }
}

}

答案 2 :(得分:1)

框架中已经没有任何内置功能可以让您执行此操作但仍有一个选项。创建自己的ValidateAntiForgeryToken实现,其中包含您希望其验证的http verb/actions参数。最简单的方法是实现接口IAuthorizationFilter

答案 3 :(得分:1)

您可以检测到此see link

if (HttpContext.Current.Request.HttpMethod == "POST")
{
    // The action is a POST.
}

并且您需要在运行操作之前拦截方法属性,并采取不同的行为来跳过操作。 ValidateAntiForgeryToken未在GET Using MVC3's AntiForgeryToken in HTTP GET to avoid Javascript CSRF vulnerability上投放。