Убедитесь, что каждый метод контроллера имеет атрибут ValidateAntiForgeryToken?
Есть ли способ централизовать принудительное выполнение, чтобы каждый метод действия имел атрибут "ValidateAntiForgeryToken"? Я думаю, что это нужно сделать, расширив классы "маршрутизации".
Изменить: Или может быть некоторое отражение при запуске приложения?
Ответы
Ответ 1
Да. Вы можете сделать это, создав свой собственный BaseController, который наследует Mvc-контроллер, и перегружает OnAuthorization(). Вы должны убедиться, что это событие POST, прежде чем принудительно выполнить его:
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,
System.Net.WebRequestMethods.Http.Post, true) == 0)
{
var forgery = new ValidateAntiForgeryTokenAttribute();
forgery.OnAuthorization(filterContext);
}
base.OnAuthorization(filterContext);
}
}
После этого убедитесь, что все ваши контроллеры наследуются от этого MyBaseController (или как вы его называете). Или вы можете сделать это на каждом контроллере, если хотите, с тем же кодом.
Ответ 2
Похоже, вы пытаетесь предотвратить "oops, я забыл установить эти" ошибки. Если это так, я думаю, что лучшее место для этого - это настраиваемый контроллер ControllerActionInvoker.
По сути, вы хотите остановить MVC даже от поиска действия без токена AntiForgery:
public class MustHaveAntiForgeryActionInvoker : ControllerActionInvoker
{
protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
{
var foundAction = base.FindAction(controllerContext, controllerDescriptor, actionName);
if( foundAction.GetCustomAttributes(typeof(ValidateAntiForgeryTokenAttribute), true ).Length == 0 )
throw new InvalidOperationException("Can't find a secure action method to execute");
return foundAction;
}
}
Затем в вашем контроллере, предпочтительно, ваш базовый контроллер:
ActionInvoker = new MustHaveAntiForgeryActionInvoker();
Просто хотелось добавить, что пользовательские базовые классы Controller имеют тенденцию "толсто" и использовать свою оптимальную практику для использования превосходных точек расширяемости MVC для привязки функций, которые вам нужны, когда они принадлежат.
Вот хорошее руководство по большей части точек расширения MVC:
http://codeclimber.net.nz/archive/2009/04/08/13-asp.net-mvc-extensibility-points-you-have-to-know.aspx
Ответ 3
Хорошо, я просто обновил проект до MVC v2.0 здесь, а решение eduncan911 больше не работает, если вы используете AuthorizeAttribute
для действий вашего контроллера. Было сложно понять, почему.
Итак, виновником в истории является то, что команда MVC добавила использование свойства ViewContext.HttpContext.User.Identity.Name
в значение для RequestVerificationToken
.
Переопределенный OnAuthorization
в базовом контроллере выполняется перед любыми фильтрами в действии контроллера. Таким образом, проблема в том, что атрибут Authorize еще не был вызван и, следовательно, не установлен ViewContext.HttpContext.User
. Таким образом, UserName является String.Empty, тогда как AntiForgeryToken, используемый для проверки, включает в себя действительное имя пользователя = fail.
Мы решили это теперь с помощью этого кода:
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);
}
}
Некоторые ссылки на базу кода MVC:
ControllerActionInvoker#InvokeAuthorizationFilters()
строка 283. То же короткое замыкание.
AntiForgeryData#GetUsername()
строка 98. Новая функциональность.
Ответ 4
Как насчет этого?
[ValidateAntiForgeryToken]
public class MyBaseController : Controller
{
}