ValidateAntiForgeryToken не работает asp.net mvc с сообщением ajax

У меня есть приложение ASP.NET MVC 5 с использованием .Net 4.5.1. В приложении есть несколько методов JQuery ajax post, которые отправляют данные POST на сервер. Чтобы предотвратить подделку межсайтовых запросов (XSRF), я добавил следующее в _layout.cshtml

 @Html.AntiForgeryToken()

а также javascript, который отправляет токен со всем ajax POST в HttpHeader

$(document).ajaxSend(function (event, jqXHR, ajaxOptions) {
            if (ajaxOptions.type === 'POST') {
                jqXHR.setRequestHeader('__RequestVerificationToken', $('input[name="__RequestVerificationToken"]').val());
            }                
        });

а затем в методе действия контроллера у меня есть

    [ValidateAntiForgeryToken]        
    [HttpPost]
    public ActionResult Save(MyModel model)
    {
       //save and return json data
    }

Однако исключение ValidateAntiForgeryToken Thorwing

Отсутствует обязательное поле формы защиты от подделки «__RequestVerificationToken».

Я проверил, что __RequestVerificationToken добавляется в httpheader для каждого запроса Ajax POST.

У меня есть другое приложение, которое было разработано с использованием ASP.NET Core, и у меня там такая же функциональность (за исключением того, что имя заголовка RequestVerificationToken вместо __RequestVerificationToken), и оно работает в ASP.NET Core.

Почему то же самое не работает в ASP.NET MVC, когда токен включен в заголовок? Есть ли разница между ValidateAntiForgeryToken в ASP.NET Core и ASP.NET MVC 5?


person LP13    schedule 23.02.2017    source источник
comment
Возможный дубликат вызовов jQuery Ajax и Html.AntiForgeryToken ()   -  person VahidN    schedule 24.02.2017
comment
@VahidN это не та же проблема. Я уже проходил по указанной ссылке раньше.   -  person LP13    schedule 24.02.2017


Ответы (2)


Чтобы решить вашу проблему, все остается прежним, кроме setRequestHeader. Передайте __RequestVerificationToken в теле запроса

data: {
                __RequestVerificationToken: $('input[name="__RequestVerificationToken"]').val(),
                // Other properties of data
            },
person Kaushal    schedule 24.02.2017
comment
да в asp.net mvc, если я добавлю к данным, то он будет работать? однако я думаю, что в ядре asp.net он работает независимо от того, добавляете ли вы data или в header. Чтобы решить свою проблему, я реализовал собственный атрибут ValidateAntiForgeryTokenAttribute. - person LP13; 24.02.2017
comment
Ядро Asp.net проверяет заголовок и тело на предмет наличия токена. - person Kaushal; 24.02.2017

Чтобы решить свою проблему, я реализовал собственный ValidateAntiForgeryToken. Я решил включить токен в заголовок.

  1. У меня есть несколько методов Ajax POST во всем приложении, поэтому вместо добавления его в каждый метод действия я хочу проверить его глобально.
  2. На стороне клиента я хочу неявно включать токен для каждого запроса POST ajax. (в приложении также есть сетки kendo, которые отправляют запрос на отправку ajax для получения данных)
  3. Сообщение ajax data может быть json-объектом или сериализованной формой, что делает добавление __RequestVerificationToken в data немного сложным (не невозможным), особенно когда я хочу обрабатывать его глобально.

Итак, вот мой полный код

Фильтр

public class ValidatePostAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
    {
        private const string _tokenKey = "__RequestVerificationToken";
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }

            if (filterContext.HttpContext.Request.HttpMethod.ToUpper() == "POST")
            {
                if (filterContext.HttpContext.Request.IsAjaxRequest())
                {
                    if (filterContext.HttpContext.Request.Cookies.Get(_tokenKey) == null ||
                    filterContext.HttpContext.Request.Headers.Get(_tokenKey) == null)
                    {
                        throw new HttpPostAntiForgeryException("Invalid Verification Token.");
                    }

                    AntiForgery.Validate(filterContext.HttpContext.Request.Cookies[_tokenKey].Value, filterContext.HttpContext.Request.Headers[_tokenKey]);
                }                
            }
        }
    }

Исключение

public sealed class HttpPostAntiForgeryException : HttpException
{
    public HttpPostAntiForgeryException()
    {
    }
    public HttpPostAntiForgeryException(string message) : base(message)
    {
    }
}

Добавить глобальный фильтр

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new AuthorizeAttribute() { Order = 0 });
        filters.Add(new ValidatePostAntiForgeryTokenAttribute() { Order = 1 });
    }
}

_layout.cshtml - js для добавления токена

 $.ajaxPrefilter(function (options, originalOptions, jqXHR) {
                if (originalOptions.type === "POST")
                    jqXHR.setRequestHeader('__RequestVerificationToken', $('input[name="__RequestVerificationToken"]').val());
            });

Добавить токен в _layout.cshtml

  @Html.AntiForgeryToken()
person LP13    schedule 24.02.2017