Убедитесь, что каждый метод контроллера имеет атрибут 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
{
}