Reputation: 197
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
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
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
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
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