JQuery Ajax вызывает и Html.AntiForgeryToken ()

207

Я реализовал в своем приложении защиту от CSRF-атак, следуя информации, которую я прочитал в блоге в Интернете. В частности, этот пост был драйвером моей реализации

В основном в этих статьях и рекомендациях говорится, что для предотвращения атаки CSRF любой должен реализовать следующий код:

1) Добавьте [ValidateAntiForgeryToken]на каждое действие, которое принимает глагол POST Http

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SomeAction( SomeModel model ) {
}

2) Добавьте <%= Html.AntiForgeryToken() %>помощника внутри формы, которая передает данные на сервер

<div style="text-align:right; padding: 8px;">
    <%= Html.AntiForgeryToken() %>
    <input type="submit" id="btnSave" value="Save" />
</div>

Во всяком случае, в некоторых частях моего приложения я выполняю POST Ajax с jQuery на сервере, не имея никакой формы. Это происходит, например, когда я позволяю пользователю нажимать на изображение для выполнения определенного действия.

Предположим, у меня есть таблица со списком мероприятий. У меня есть изображение в столбце таблицы с надписью «Пометить активность как выполненную», и когда пользователь нажимает на эту активность, я выполняю Ajax POST, как в следующем примере:

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {},
        success: function (response) {
            // ....
        }
    });
});

Как я могу использовать <%= Html.AntiForgeryToken() %>в этих случаях? Должен ли я включить вспомогательный вызов в параметр данных вызова Ajax?

Извините за длинный пост и большое спасибо за помощь

РЕДАКТИРОВАТЬ :

Согласно jayrdub ответа я использовал следующий образ

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: {
            AddAntiForgeryToken({}),
            id: parseInt($(this).attr("title"))
        },
        success: function (response) {
            // ....
        }
    });
});
Lorenzo
источник
Ссылка David Hayden Теперь ошибки 404, кажется , что он мигрировал свой блог на новую CMS, но не мигрировали весь старый контент через.

Ответы:

252

Я использую простую функцию JS, как это

AddAntiForgeryToken = function(data) {
    data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
    return data;
};

Поскольку каждая форма на странице будет иметь одинаковое значение для токена, просто поместите что-то вроде этого на свою самую верхнюю главную страницу

<%-- used for ajax in AddAntiForgeryToken() --%>
<form id="__AjaxAntiForgeryForm" action="#" method="post"><%= Html.AntiForgeryToken()%></form>  

Затем в вашем вызове ajax do (отредактировано в соответствии с вашим вторым примером)

$.ajax({
    type: "post",
    dataType: "html",
    url: $(this).attr("rel"),
    data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
    success: function (response) {
        // ....
    }
});
JeremyWeir
источник
6
Хорошо, мне нравится инкапсуляция извлечения токена.
Jball
2
@Lorenzo, добавь свои собственные данные в вызов AddAntiForgeryToken, вот так:data: AddAntiForgeryToken({ id: parseInt($(this).attr("title")) }),
jball
3
Насколько плоха была бы идея использовать ajaxSendили переопределить, ajaxчтобы всегда дополнять dataтокеном против подделки? Может быть, добавив некоторые проверки, чтобы убедиться, что urlпредназначен для вашего сервера.
ta.speot.is
1
Будьте осторожны, если вы используете кеш вывода.
Барбарос Алп
1
@SouhaiebBesbes токен проверки должен быть одинаковым для пользователя на всех страницах (он работает в сочетании с установленным файлом cookie и остается таким же). Таким образом, не имеет значения, если есть несколько запросов на страницу, все равно будет, если базовая страница перезагрузится в любом случае.
JeremyWeir
29

Мне нравится решение, предоставляемое 360Airwalk, но оно может быть немного улучшено.

Первая проблема заключается в том, что если вы делаете $.post()с пустыми данными, jQuery не добавляет Content-Typeзаголовок, и в этом случае ASP.NET MVC не может получить и проверить токен. Таким образом, вы должны убедиться, что заголовок всегда там.

Другим улучшением является поддержка всех HTTP-глаголов с содержимым : POST, PUT, DELETE и т. Д. Хотя вы можете использовать только POST в своем приложении, лучше иметь общее решение и убедиться, что все данные, которые вы получаете с любым глаголом, имеют защиту от подделки. маркер.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $(document).ajaxSend(function (event, request, opt) {
        if (opt.hasContent && securityToken) {   // handle all verbs with content
            var tokenParam = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            opt.data = opt.data ? [opt.data, tokenParam].join("&") : tokenParam;
            // ensure Content-Type header is present!
            if (opt.contentType !== false || event.contentType) {
                request.setRequestHeader( "Content-Type", opt.contentType);
            }
        }
    });
});
Бронкс
источник
1
+1 вы правы, я не задумывался о проблеме пустых звонков. спасибо за вклад. вы были правы насчет того, что мы еще не используем delete / put в нашем проекте.
360Airwalk 19.09.12
2
+1 за избавление от необходимости добавлять функцию ко всем вызовам jQuery.Ajax
Dragos Durlut
2
+1 Так же, как примечание для потомков, документация jQuery для .ajaxSend()состояний «Начиная с jQuery 1.8, метод .ajaxSend () должен быть прикреплен только к документу». api.jquery.com/ajaxsend
Р. Дж. Катбертсон,
1
@ Бронкс Откуда взято options, что указано в окончательном ifутверждении? Спасибо.
hvaughan3
Остерегайтесь использовать это, если у вас есть несколько форм на странице. Вам нужно будет установить значение в beforeSend с более конкретным вызовом селектора вместо документа.
Дэн
22

Я знаю, что есть много других ответов, но эта статья хороша и лаконична и заставляет вас проверять все ваши HttpPosts, а не только некоторые из них:

http://richiban.wordpress.com/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/

Он использует заголовки HTTP вместо попытки изменить коллекцию форм.

сервер

//make sure to add this to your global action filters
[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public override void OnAuthorization( AuthorizationContext filterContext )
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value 
                    : null;

                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

клиент

var token = $('[name=__RequestVerificationToken]').val();
var headers = {};
headers["__RequestVerificationToken"] = token;

$.ajax({
    type: 'POST',
    url: '/Home/Ajax',
    cache: false,
    headers: headers,
    contentType: 'application/json; charset=utf-8',
    data: { title: "This is my title", contents: "These are my contents" },
    success: function () {
        ...
    },
    error: function () {
        ...
    }
});
viggity
источник
4
Атрибут из статьи, которую вы тоже связали, в сочетании с ответом Бронкса - окончательное СУХОЕ решение этой проблемы.
TugboatCaptain
2
Отличная находка. Я отредактировал ваш ответ, включив в него фрагменты кода, так что ответ стоит сам по себе, но я надеюсь, что люди прочтут и остальную часть статьи. Похоже, это очень чистое решение.
Тим Медора
спасибо Тим, это отличная идея, она расстраивает, когда ссылка обрывается и ответ становится бесполезным. Я начал делать это на всех моих новых ответах.
бодрость
Это MVC, WebAPI или .NetCore? Я не могу получить правильные пространства имен для WebAPI 5
Myster
20

Я чувствую себя продвинутым некромантом здесь, но это все еще проблема 4 года спустя в MVC5.

Для правильной обработки ajax-запросов токен защиты от подделки должен передаваться на сервер при ajax-вызовах. Интеграция его в ваши почтовые данные и модели является грязной и ненужной. Добавление токена в качестве пользовательского заголовка является чистым и пригодным для повторного использования - и вы можете настроить его так, чтобы вам не приходилось делать это каждый раз.

Есть исключение - ненавязчивый ajax не требует специальной обработки для вызовов ajax. Маркер передается как обычно в обычном скрытом поле ввода. Точно так же, как обычный пост.

_Layout.cshtml

В _layout.cshtml у меня есть этот блок JavaScript. Он не записывает токен в DOM, а использует jQuery для извлечения его из скрытого входного литерала, который генерирует помощник MVC. Волшебная строка, которая является именем заголовка, определяется как константа в классе атрибута.

<script type="text/javascript">
    $(document).ready(function () {
        var isAbsoluteURI = new RegExp('^(?:[a-z]+:)?//', 'i');
        //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative

        $.ajaxSetup({
            beforeSend: function (xhr) {
                if (!isAbsoluteURI.test(this.url)) {
                    //only add header to relative URLs
                    xhr.setRequestHeader(
                       '@.ValidateAntiForgeryTokenOnAllPosts.HTTP_HEADER_NAME', 
                       $('@Html.AntiForgeryToken()').val()
                    );
                }
            }
        });
    });
</script>

Обратите внимание на использование одинарных кавычек в функции beforeSend - в отображаемом элементе ввода используются двойные кавычки, которые разбивают литерал JavaScript.

Клиентский JavaScript

Когда это выполняется, вызывается указанная выше функция beforeSend, и AntiForgeryToken автоматически добавляется в заголовки запроса.

$.ajax({
  type: "POST",
  url: "CSRFProtectedMethod",
  dataType: "json",
  contentType: "application/json; charset=utf-8",
  success: function (data) {
    //victory
  }
});

Серверная библиотека

Пользовательский атрибут необходим для обработки нестандартного токена. Это основано на решении @ viggity, но правильно обрабатывает ненавязчивый Ajax. Этот код можно спрятать в вашей общей библиотеке

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class ValidateAntiForgeryTokenOnAllPosts : AuthorizeAttribute
{
    public const string HTTP_HEADER_NAME = "x-RequestVerificationToken";

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {

            var headerTokenValue = request.Headers[HTTP_HEADER_NAME];

            // Ajax POSTs using jquery have a header set that defines the token.
            // However using unobtrusive ajax the token is still submitted normally in the form.
            // if the header is present then use it, else fall back to processing the form like normal
            if (headerTokenValue != null)
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value
                    : null;

                AntiForgery.Validate(cookieValue, headerTokenValue);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

Сервер / Контроллер

Теперь вы просто применяете атрибут к своему действию. Еще лучше, вы можете применить атрибут к контроллеру, и все запросы будут проверены.

[HttpPost]
[ValidateAntiForgeryTokenOnAllPosts]
public virtual ActionResult CSRFProtectedMethod()
{
  return Json(true, JsonRequestBehavior.DenyGet);
}
Будет D
источник
Идеальное решение, гораздо более централизованное. Спасибо
Дэвид Фрейр
Можете ли вы объяснить более подробно, почему вы хотите добавить заголовок только для относительных URL? Это прошло над моей головой. Отличное решение!
15:30
относительный гарантирует, что заголовок устанавливается только для запросов, возвращающихся на ваш собственный сервер, так как настройка ajax охватывает все запросы, сделанные с помощью jquery, мы не хотим, чтобы токен отправлялся по запросам jsonp или CORS. Это может быть верно и для абсолютных URL, но относительный гарантированно будет одним доменом.
Будет ли
1
@WillD Мне понравилось ваше решение, но я был вынужден немного его изменить. Поскольку вы выбираете $.ajaxSetupопределение общего beforesendобработчика событий, может случиться так, что вы перезапишете его. Я нашел другое решение, где вы можете добавить второй обработчик, который также будет вызываться. Работает хорошо и не нарушает вашу реализацию.
Viper
У кого-нибудь есть ASP.net 5 версия клиента, проверяющая атрибут AntiForgery? Эта версия не компилируется в последней версии!
Роб МакКейб
19

Не используйте Html.AntiForgeryToken . Вместо этого используйте AntiForgery.GetTokens и AntiForgery.Validate из Web API, как описано в разделе Предотвращение атак подделки межсайтовых запросов (CSRF) в приложении ASP.NET MVC .

Эдвард Брей
источник
Для методов действия контроллера, которые связывают модель модели типа сервера с опубликованным AJAX JSON, для использования правильного связывателя модели требуется тип контента «application / json». К сожалению, это исключает использование данных формы, требуемых атрибутом [ValidateAntiForgeryToken], поэтому ваш метод - единственный способ, который я смог найти, чтобы заставить его работать. Единственный вопрос: работает ли он в веб-ферме или в нескольких экземплярах веб-роли Azure? Вы @Edward или кто-нибудь еще знает, если это проблема?
Ричард Б
@ Эдвард Брей Не могли бы вы рассказать, почему мы не должны его использовать?
Одис
4
@Odys: По сути, в Html.AntiForgeryToken нет ничего плохого, но у него есть недостатки: требуется форма, требуется jQuery и предполагаются недокументированные детали реализации Html.AntiForgeryToken. Тем не менее, это хорошо во многих контекстах. Мое утверждение «Не используйте Html.AntiForgeryToken», вероятно, звучит слишком сильно. Я имею в виду, что он не предназначен для использования с веб-API, в то время как более гибкий AntiForgery.GetTokens.
Эдвард Брей
Спасибо! Я должен был изменить его немного , чтобы заставить его работать на контроллер MVC5, но это было решение
Джао
3
Это, конечно, не требует формы. Вам просто нужно разобрать DOM для этого по имени. Используя jquery, я могу добавить его в свой объект данных через data {__RequestVerificationToken: $ ("input [name = __ RequestVerificationToken]"). Val ()}
Энтони Мейсон
16

Я только что реализовал эту актуальную проблему в моем текущем проекте. Я сделал это для всех ajax-POST, которые нуждались в аутентифицированном пользователе.

Во-первых, я решил перехватить мои jjery ajax-звонки, чтобы не повторяться слишком часто. этот фрагмент javascript гарантирует, что все вызовы ajax (post) добавят в запрос маркер проверки моего запроса. Примечание: имя __RequestVerificationToken используется платформой .Net, поэтому я могу использовать стандартные функции Anti-CSRF, как показано ниже.

$(document).ready(function () {
    var securityToken = $('[name=__RequestVerificationToken]').val();
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});

В ваших представлениях, где вам нужно, чтобы токен был доступен для вышеуказанного javascript, просто используйте общий HTML-помощник. Вы можете добавить этот код везде, где хотите. Я поместил его в оператор if (Request.IsAuthenticated):

@Html.AntiForgeryToken() // you can provide a string as salt when needed which needs to match the one on the controller

В вашем контроллере просто используйте стандартный механизм ASP.Net MVC Anti-CSRF. Я сделал это так (хотя я на самом деле использовал соль).

[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public JsonResult SomeMethod(string param)
{
    // do something
    return Json(true);
}

С помощью Firebug или аналогичного инструмента вы можете легко увидеть, как к вашим запросам POST теперь добавлен параметр __RequestVerificationToken.

360Airwalk
источник
15

Я думаю, все, что вам нужно сделать, это убедиться, что вход «__RequestVerificationToken» включен в запрос POST. Другая половина информации (то есть токен в файле cookie пользователя) уже автоматически отправляется с запросом AJAX POST.

Например,

$("a.markAsDone").click(function (event) {
    event.preventDefault();
    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: { 
            "__RequestVerificationToken":
            $("input[name=__RequestVerificationToken]").val() 
        },
        success: function (response) {
            // ....
        }
    });
});
jball
источник
1
После многих часов экспериментирования с публикацией jQuery AJAX со страницы MVC (Razor), это был самый простой ответ из всех, которые у меня работали. Просто добавьте свои собственные поля данных (или, я полагаю, viewModel) после токена как новый фрагмент данных (но внутри исходного объекта данных).
Ральф Бэкон
Как бы я это реализовал, если бы функция AJAX была на странице .html, а не на странице Razor?
Боб Строитель
Если ваша html-страница не снабжена сервером, AntiForgeryTokenэто все равно будет спорным. Если это так (не уверен, как вы получаете один в этом случае, но при условии, что вы), то вышеописанное будет работать просто отлично. Если вы пытаетесь создать простую веб-страницу, которая отправит запрос на сервер, ожидающий указанный токен, и сервер не сгенерировал указанную страницу, то вам не повезло. В этом и заключается смысл AntiForgeryToken ...
jball
6

Вы можете сделать это также:

$("a.markAsDone").click(function (event) {
    event.preventDefault();

    $.ajax({
        type: "post",
        dataType: "html",
        url: $(this).attr("rel"),
        data: $('<form>@Html.AntiForgeryToken()</form>').serialize(),
        success: function (response) {
        // ....
        }
    });
});

Это использует Razor, но если вы используете WebFormsсинтаксис, вы можете также использовать <%= %>теги

Леонардо Гарсия Креспо
источник
4

В дополнение к моему комментарию против ответа @ JBall, который помог мне на этом пути, это последний ответ, который работает для меня. Я использую MVC и Razor и отправляю форму с использованием jQuery AJAX, чтобы я мог обновить частичное представление с некоторыми новыми результатами, и я не хотел делать полный постбэк (и мерцание страницы).

Добавьте @Html.AntiForgeryToken()внутри форму как обычно.

Мой код кнопки отправки AJAX (то есть событие onclick):

//User clicks the SUBMIT button
$("#btnSubmit").click(function (event) {

//prevent this button submitting the form as we will do that via AJAX
event.preventDefault();

//Validate the form first
if (!$('#searchForm').validate().form()) {
    alert("Please correct the errors");
    return false;
}

//Get the entire form's data - including the antiforgerytoken
var allFormData = $("#searchForm").serialize();

// The actual POST can now take place with a validated form
$.ajax({
    type: "POST",
    async: false,
    url: "/Home/SearchAjax",
    data: allFormData,
    dataType: "html",
    success: function (data) {
        $('#gridView').html(data);
        $('#TestGrid').jqGrid('setGridParam', { url: '@Url.Action("GetDetails", "Home", Model)', datatype: "json", page: 1 }).trigger('reloadGrid');
    }
});

Я оставил действие "success", так как оно показывает, как обновляется частичное представление, содержащее MvcJqGrid и как оно обновляется (очень мощная сетка jqGrid, и это блестящая оболочка MVC для нее).

Мой метод контроллера выглядит так:

    //Ajax SUBMIT method
    [ValidateAntiForgeryToken]
    public ActionResult SearchAjax(EstateOutlet_D model) 
    {
        return View("_Grid", model);
    }

Я должен признать, что не являюсь поклонником размещения данных всей формы как модели, но если вам нужно сделать это, то это один из способов, который работает. MVC просто делает привязку данных слишком легкой, поэтому вместо подстановки 16 отдельных значений (или слабо типизированной формы FormCollection) это нормально, я полагаю. Если вы знаете лучше, пожалуйста, дайте мне знать, так как я хочу создать надежный код MVC C #.

Ральф Бэкон
источник
4

нашел эту очень умную идею из https://gist.github.com/scottrippey/3428114 для каждого вызова $ .ajax, он изменяет запрос и добавляет токен.

// Setup CSRF safety for AJAX:
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
    if (options.type.toUpperCase() === "POST") {
        // We need to add the verificationToken to all POSTs
        var token = $("input[name^=__RequestVerificationToken]").first();
        if (!token.length) return;

        var tokenName = token.attr("name");

        // If the data is JSON, then we need to put the token in the QueryString:
        if (options.contentType.indexOf('application/json') === 0) {
            // Add the token to the URL, because we can't add it to the JSON data:
            options.url += ((options.url.indexOf("?") === -1) ? "?" : "&") + token.serialize();
        } else if (typeof options.data === 'string' && options.data.indexOf(tokenName) === -1) {
            // Append to the data string:
            options.data += (options.data ? "&" : "") + token.serialize();
        }
    }
});
masterlopau
источник
Я попробовал несколько других вариантов выше, это то, что решил для меня.
HostMyBus,
Однако я должен был добавить, if (options.contentType != false && options.contentType.indexOf('application/json') === 0) {чтобы перехватывать вызовы Ajax, которые не указали тип содержимого
HostMyBus,
3

1. Определить функцию для получения токена с сервера

@function
{

        public string TokenHeaderValue()
        {
            string cookieToken, formToken;
            AntiForgery.GetTokens(null, out cookieToken, out formToken);
            return cookieToken + ":" + formToken;                
        }
}

2. Получить токен и установить заголовок перед отправкой на сервер

var token = '@TokenHeaderValue()';    

       $http({
           method: "POST",
           url: './MainBackend/MessageDelete',
           data: dataSend,
           headers: {
               'RequestVerificationToken': token
           }
       }).success(function (data) {
           alert(data)
       });

3. Проверка сервера на HttpRequestBase для метода, который вы обрабатываете Post / get

        string cookieToken = "";
        string formToken = "";
        string[] tokens = Request.Headers["RequestVerificationToken"].Split(':');
            if (tokens.Length == 2)
            {
                cookieToken = tokens[0].Trim();
                formToken = tokens[1].Trim();
            }
        AntiForgery.Validate(cookieToken, formToken);
Тонман Неверволк один
источник
1

Я знаю, что прошло некоторое время с тех пор, как этот вопрос был опубликован, но я нашел действительно полезный ресурс, который обсуждает использование AntiForgeryToken и делает его менее трудным для использования. Он также предоставляет плагин jquery для простого включения токена защиты от подделки в вызовы AJAX:

Рецепты против подделки запроса для ASP.NET MVC и AJAX

Я не очень помогаю, но, возможно, кто-то найдет это полезным.

Slawek
источник
Этот пост длиной в милю! Я уверен, что это здорово, но tl; dr
BritishDeveloper
1
Слишком плохо, потому что это хорошо покрывает предмет. Он не только говорит вам, как использовать функцию, но и объясняет, какую проблему она исправляет, и дает вам контекст, чтобы понять, как правильно ее использовать. Когда дело доходит до безопасности, я думаю, что глубокое понимание важно.
slawek
2
Если это важно, это должно быть написано так, чтобы люди могли его прочитать;)
BritishDeveloper,
1

сначала используйте @ Html.AntiForgeryToken () в html

 $.ajax({
        url: "@Url.Action("SomeMethod", "SomeController")",
        type: 'POST',
        data: JSON.stringify(jsonObject),
        contentType: 'application/json; charset=utf-8',
        dataType: 'json',
        async: false,
        beforeSend: function (request) {
            request.setRequestHeader("RequestVerificationToken", $("[name='__RequestVerificationToken']").val());
        },
        success: function (msg) {
            alert(msg);
        }
Амир Реза
источник
1

Вот самый простой способ, который я видел. Примечание. Убедитесь, что у вас в представлении «@ Html.AntiForgeryToken ()»

  $("a.markAsDone").click(function (event) {
        event.preventDefault();
        var sToken = document.getElementsByName("__RequestVerificationToken")[0].value;
        $.ajax({
            url: $(this).attr("rel"),
            type: "POST",
            contentType: "application/x-www-form-urlencoded",
            data: { '__RequestVerificationToken': sToken, 'id': parseInt($(this).attr("title")) }
        })
        .done(function (data) {
            //Process MVC Data here
        })
        .fail(function (jqXHR, textStatus, errorThrown) {
            //Process Failure here
        });
    });
Доминик Спуто
источник
0

Небольшое улучшение для решения 360Airwalk. Это вставляет токен Anti Forgery в функцию javascript, поэтому @ Html.AntiForgeryToken () больше не нужно включать в каждое представление.

$(document).ready(function () {
    var securityToken = $('@Html.AntiForgeryToken()').attr('value');
    $('body').bind('ajaxSend', function (elm, xhr, s) {
        if (s.type == 'POST' && typeof securityToken != 'undefined') {
            if (s.data.length > 0) {
                s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
            else {
                s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
            }
        }
    });
});
Барри MSIH
источник
0
function DeletePersonel(id) {

    var data = new FormData();
    data.append("__RequestVerificationToken", "@HtmlHelper.GetAntiForgeryToken()");

    $.ajax({
        type: 'POST',
        url: '/Personel/Delete/' + id,
        data: data,
        cache: false,
        processData: false,
        contentType: false,
        success: function (result) {
        }
    });
}

public static class HtmlHelper {
    public static string GetAntiForgeryToken() {
        System.Text.RegularExpressions.Match value = 
                System.Text.RegularExpressions.Regex.Match(System.Web.Helpers.AntiForgery.GetHtml().ToString(), 
                        "(?:value=\")(.*)(?:\")");
        if (value.Success) {
            return value.Groups[1].Value;
        }
        return "";
    }
}
Исмаил Эски
источник
0

Я использую сообщение ajax для запуска метода удаления (происходит из временной шкалы visjs, но это не очень важно). Это то, что я сестренка:

Это мой Index.cshtml

@Scripts.Render("~/bundles/schedule")
@Styles.Render("~/bundles/visjs")
@Html.AntiForgeryToken()

<!-- div to attach schedule to -->
<div id='schedule'></div>

<!-- div to attach popups to -->
<div id='dialog-popup'></div>

Все, что я добавил здесь, это @Html.AntiForgeryToken()чтобы токен появился на странице.

Тогда в своем посте ajax я использовал:

$.ajax(
    {
        type: 'POST',
        url: '/ScheduleWorks/Delete/' + item.id,
        data: {
            '__RequestVerificationToken': 
            $("input[name='__RequestVerificationToken']").val()
              }
     }
);

Который добавляет значение токена, удаленное со страницы, к опубликованным полям

До этого я пытался поместить значение в заголовки, но я получил ту же ошибку

Не стесняйтесь размещать улучшения. Это, конечно, кажется простым подходом, который я могу понять

Nick.McDermaid
источник
0

Хорошо, здесь много постов, ни одно из них не помогло мне, дни и дни Google, и до сих пор я больше не дошел до того, что написал все приложение с нуля, а потом заметил этот маленький самородок в моем Web.confg.

 <httpCookies requireSSL="false" domain="*.localLookup.net"/>

Теперь я не знаю, почему я добавил его, однако с тех пор заметил, что он игнорируется в режиме отладки, а не в рабочем режиме (IE установлен в IIS Somewhere)

Для меня решение было одним из 2 вариантов, так как я не помню, почему я добавил его, я не могу быть уверен, что другие вещи не зависят от него, и во-вторых, доменное имя должно быть все в нижнем регистре и TLD не так, как я сделал в * .localLookup.net

Может быть, это помогает, может быть, нет. Я надеюсь, что это поможет кому-то

взволнованный
источник
0

Решение, которое я нашел, предназначено не для ASPX, а для Razor, но вполне решаемой проблемой.

Я решил это, добавив AntiForgery к запросу. Помощник HTML не создает идентификатор HTML с вызовом

@Html.AntiForgeryToken()

Чтобы добавить токен в пост-запрос, я просто добавил идентификатор AntiForgery в скрытое поле с помощью jquery:

$("input[name*='__RequestVerificationToken']").attr('id', '__AjaxAntiForgeryForm');

Это заставило контроллер принять запрос с атрибутом [ValidateAntiForgeryToken]

Доминик Санд
источник
-3

AntiforgeryToken - все еще боль, ни один из примеров выше не работал слово в слово для меня. Слишком много для там. Поэтому я объединил их всех. Нужен @ Html.AntiforgeryToken в форме, висящей вокруг iirc

Решено так:

function Forgizzle(eggs) {
    eggs.__RequestVerificationToken =  $($("input[name=__RequestVerificationToken]")[0]).val();
    return eggs;
}

$.ajax({
            url: url,
            type: 'post',
            data: Forgizzle({ id: id, sweets: milkway }),
});

Если сомневаетесь, добавьте больше знаков $

Хазза
источник