убедиться, что у каждого метода контроллера есть атрибут ValidateAntiForgeryToken? - PullRequest
16 голосов
/ 21 декабря 2009

Есть ли способ централизовать принудительное применение, чтобы у каждого метода действия был атрибут ValidateAntiForgeryToken? Я думаю, что это должно быть сделано путем расширения одного класса «маршрутизации».

Редактировать: Или, может быть, задуматься при запуске приложения?

Ответы [ 4 ]

22 голосов
/ 21 декабря 2009

Да. Вы можете сделать это, создав собственный BaseController, который наследует Mvc Controller и перегружает 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 (или как вы его называете). Или вы можете сделать это на каждом контроллере, если вам нравится с тем же кодом.

8 голосов
/ 21 декабря 2009

Звучит так, будто вы пытаетесь предотвратить ошибки "ой, я забыл установить". Если так, то я думаю, что лучшее место для этого - пользовательский 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

7 голосов
/ 29 марта 2010

Хорошо, я только что обновил проект до 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. Новая функциональность.

1 голос
/ 16 декабря 2013

Как насчет этого?

[ValidateAntiForgeryToken]
public class MyBaseController : Controller
{
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...