Ok, I just upgraded a project to MVC v2.0 here, and eduncan911's solution doesn't work anymore if you use the AuthorizeAttribute
on your controller actions. It was somewhat hard to figure out why.
So, the culprit in the story is that the MVC team added the use of the ViewContext.HttpContext.User.Identity.Name
property in the value for the RequestVerificationToken
.
The overridden OnAuthorization
in the base controller is executed before any filters on the controller action. So, the problem is that the Authorize attribute has not yet been invoked and therefore is the ViewContext.HttpContext.User
not set. So the UserName is String.Empty whereas the AntiForgeryToken used for validation includes the real user name = fail.
We solved it now with this code:
public abstract class MyBaseController : Controller
{
protected override void OnAuthorization(AuthorizationContext filterContext)
{
//enforce anti-forgery stuff for HttpVerbs.Post
if (String.Compare(filterContext.HttpContext.Request.HttpMethod, "post", true) == 0)
{
var authorize = new AuthorizeAttribute();
authorize.OnAuthorization(filterContext);
if (filterContext.Result != null) // Short circuit validation
return;
var forgery = new ValidateAntiForgeryTokenAttribute();
forgery.OnAuthorization(filterContext);
}
base.OnAuthorization(filterContext);
}
}
Some references to the MVC code base:
ControllerActionInvoker#InvokeAuthorizationFilters()
line 283. Same short circuiting.
AntiForgeryData#GetUsername()
line 98. New functionality.