2

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

6

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();
}
  • works, though used if (Request.HttpMethod == WebRequestMethods.Http.Post) instead for the if statement as Request.Method didn't exist in the controller – Sylvia Nov 10 '16 at 12:50
2

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

}

1

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.

  • @lgor, Thank you for your quick response. But I got more better solution which I marked as an answer. – Shanthini Jan 29 '16 at 13:37
  • @Shanthini - its a good answer and easy to implement BUT if you need to do this on many methods then writing the code once in a custom Filter is a better and more maintainable solution than adding the above if statement to all of your methods. – Igor Jan 29 '16 at 13:39
  • @lgor Yes. I agree. But at the moment I had this issue in only one scenario :) But I did create a custom filter for future reference; not using it now. – Shanthini Jan 29 '16 at 13:46
1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.