7

Is there a way to automatically have [ValidateAntiForgeryToken] annotation on all HTTP post methods on a controller without having to explicitly defining it?

and also is there a way to extend the MVC Html.BeginForm() helper to include the anti forgery token at all times?

and finally the purpose of doing this is to keep things consistent across the application, can there be a reason not to do this for some scenarios?

Ahsan
  • 2,488
  • 2
  • 22
  • 44
  • 1
    Have you had a look at [Chameleon Forms](https://github.com/MRCollective/ChameleonForms)? –  Jun 02 '15 at 02:02
  • @Bringer128 thanks for that, but not inclined to use a framework for achieving this one thing. – Ahsan Jun 02 '15 at 02:09
  • possible duplicate of [How to extend or override BeginForm to include a AntiForgeryToken field](http://stackoverflow.com/questions/6552830/how-to-extend-or-override-beginform-to-include-a-antiforgerytoken-field) – V-SHY Jun 02 '15 at 02:39
  • @V-SHY the answer in the question above addresses part of the problem. – Ahsan Jun 02 '15 at 02:45
  • Check out https://onallthingsweb.wordpress.com/2014/02/04/adding-asp-net-mvc-anti-forgery-tokens-to-all-post-requests-easily/ – Eddie Paz Jun 02 '15 at 05:55
  • How to add `ValidateAntiForgeryToken` to all actions. http://stackoverflow.com/questions/5213345/how-can-i-set-the-validateantiforgerytoken-globally How to include AntiForgeryToken to all forms. http://stackoverflow.com/questions/6552830/how-to-extend-or-override-beginform-to-include-a-antiforgerytoken-field – Yeldar Kurmangaliyev Jun 02 '15 at 06:09

1 Answers1

11

I was researching this topic myself and compiled full solution below and also here. It consists of few parts including AntiForgeryTokenFilterProvider and BeginSecureForm helper method. It also allows to skip validation for a single action with DisableAntiForgeryCheckAttribute.

public class AntiForgeryTokenFilterProvider : IFilterProvider
{
    public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
    {
        IEnumerable<FilterAttribute> filters = actionDescriptor.GetFilterAttributes(true);

        bool disableAntiForgery = filters.Any(f => f is DisableAntiForgeryCheckAttribute);

        string method = controllerContext.HttpContext.Request.HttpMethod;

        if (!disableAntiForgery
            && String.Equals(method, "POST", StringComparison.OrdinalIgnoreCase))
        {
            yield return new Filter(new ValidateAntiForgeryTokenAttribute(), FilterScope.Global, null);
        }
    }
}

[AttributeUsage(AttributeTargets.Method)]
public sealed class DisableAntiForgeryCheckAttribute : FilterAttribute
{
}

// Usage:
public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        //**//
        FilterProviders.Providers.Add(new AntiForgeryTokenFilterProvider());
        //**//
    }
}

// Html Helper method
public static class HtmlExtensions
{
    public static MvcForm BeginSecureForm(this HtmlHelper html, string action, string controller)
    {
        var form = html.BeginForm(action, controller);
        html.ViewContext.Writer.Write(html.AntiForgeryToken().ToHtmlString());

        return form;
    }
}
Vadim K.
  • 1,081
  • 1
  • 14
  • 26
  • 2
    Excellent summary, wish this was voted higher. Bits and pieces are scattered around the web, but this puts it all together. – Walter Apr 05 '19 at 22:10