Shanthini
Shanthini

Reputation: 197

Set ValidateAntiForgeryToken attribute to GET/POST for same action MVC5

My question is very straight forward...

I have an Action which accepts both HttpGet and HttpPost, but I want to set ValidateAntiForgeryToken attribute to the action when the http request is POST, not for HttpGet.

I can find whether the request is GET or POST inside the action, but I need to know before the action called.

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

    }

Is there any possibilities to achieve this without duplicating the action?

Thank you

Upvotes: 5

Views: 7746

Answers (4)

Matthew
Matthew

Reputation: 4339

First off, this is a very bad design. The point of MVC is to separate methods in the controller. If you want two methods to have the same behavior, I suggest amending your controller to have a GET and a POST that each call the same method elsewhere in the controller.

But you could write a Validation attribute to accomplish what you want.

Based on this source code, you could edit the OnAuthorization method in the Validation attribute to:

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

            ValidateAction();
        }
    }

which now checks to see if the request is GET in which case it skips the validation. The full Attribute class is:

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();
        }
    }
}

}

Upvotes: 3

Steven Sproat
Steven Sproat

Reputation: 4578

You could conditionally check the request's HTTP method and manually do the validation yourself:

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

Upvotes: 7

Jones
Jones

Reputation: 1500

You have possibility to detect this see link:

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

and you need a method attribute to intercept before run action and take different behavior to skip action. The ValidateAntiForgeryToken is not run on GET Using MVC3's AntiForgeryToken in HTTP GET to avoid Javascript CSRF vulnerability.

Upvotes: 1

Igor
Igor

Reputation: 62213

There is nothing already built into the framework that would currently allow you to do this but you still have one option. Create your own implementation of ValidateAntiForgeryToken that takes a parameter the http verb/actions that you want it to validate on. The easiest way is to implement interface IAuthorizationFilter.

Upvotes: 1

Related Questions