включить антифоргегокен в пост Ajax ASP.NET MVC

105

У меня возникают проблемы с AntiForgeryToken с помощью ajax. Я использую ASP.NET MVC 3. Я попробовал решение в jQuery Ajax-вызовах и Html.AntiForgeryToken(). Используя это решение, токен теперь передается:

var data = { ... } // with token, key is '__RequestVerificationToken'

$.ajax({
        type: "POST",
        data: data,
        datatype: "json",
        traditional: true,
        contentType: "application/json; charset=utf-8",
        url: myURL,
        success: function (response) {
            ...
        },
        error: function (response) {
            ...
        }
    });

Когда я удаляю атрибут [ValidateAntiForgeryToken], чтобы увидеть, передаются ли данные (с маркером) в качестве параметров для контроллера, я вижу, что они передаются. Но по какой-то причине сообщение A required anti-forgery token was not supplied or was invalid. все еще появляется, когда я возвращаю атрибут.

Любые идеи?

ИЗМЕНИТЬ

Внутри формы генерируется antiforgerytoken, но я не использую действие отправки, чтобы отправить его. Вместо этого, я просто получаю значение токена, используя jquery, а затем пытаюсь выполнить ajax post.

Вот форма, содержащая токен, и расположена на главной главной странице:

<form id="__AjaxAntiForgeryForm" action="#" method="post">
    @Html.AntiForgeryToken()
</form>
Теги:
csrf
asp.net-mvc
asp.net-mvc-3

7 ответов

192
Лучший ответ

Вы неправильно указали contentType на application/json.

Вот пример того, как это может работать.

Контроллер:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Index(string someValue)
    {
        return Json(new { someValue = someValue });
    }
}

Вид:

@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "__AjaxAntiForgeryForm" }))
{
    @Html.AntiForgeryToken()
}

<div id="myDiv" data-url="@Url.Action("Index", "Home")">
    Click me to send an AJAX request to a controller action
    decorated with the [ValidateAntiForgeryToken] attribute
</div>

<script type="text/javascript">
    $('#myDiv').submit(function () {
        var form = $('#__AjaxAntiForgeryForm');
        var token = $('input[name="__RequestVerificationToken"]', form).val();
        $.ajax({
            url: $(this).data('url'),
            type: 'POST',
            data: { 
                __RequestVerificationToken: token, 
                someValue: 'some value' 
            },
            success: function (result) {
                alert(result.someValue);
            }
        });
        return false;
    });
</script>
  • 0
    Привет, спасибо за быстрый ответ. Извините, я не упомянул об этом в вопросе; В данный момент я не использую действие отправки. (Токен находится в форме, но я не использую кнопку отправки, чтобы отправить его). Можно ли просто изменить тип контента на что-то другое?
  • 13
    Тот факт, что вы не используете действие отправки, не сильно меняет мой ответ. Все, что вам нужно сделать, это подписаться на какое-то другое событие (нажатие кнопки, щелчок привязки или что-то еще и просто прочитать значение скрытого поля). Что касается отправки запроса AJAX, вы можете использовать пример, приведенный в моем ответе. Не следует использовать contentType для application/json потому что сервер ожидает, что параметр __RequestVerificationToken будет частью полезной нагрузки POST-запроса с использованием application/x-www-form-urlencoded .
Показать ещё 7 комментариев
46

Другой (менее javascriptish) подход, который я сделал, выглядит примерно так:

Во-первых, html-помощник

public static MvcHtmlString AntiForgeryTokenForAjaxPost(this HtmlHelper helper)
{
    var antiForgeryInputTag = helper.AntiForgeryToken().ToString();
    // Above gets the following: <input name="__RequestVerificationToken" type="hidden" value="PnQE7R0MIBBAzC7SqtVvwrJpGbRvPgzWHo5dSyoSaZoabRjf9pCyzjujYBU_qKDJmwIOiPRDwBV1TNVdXFVgzAvN9_l2yt9-nf4Owif0qIDz7WRAmydVPIm6_pmJAI--wvvFQO7g0VvoFArFtAR2v6Ch1wmXCZ89v0-lNOGZLZc1" />
    var removedStart = antiForgeryInputTag.Replace(@"<input name=""__RequestVerificationToken"" type=""hidden"" value=""", "");
    var tokenValue = removedStart.Replace(@""" />", "");
    if (antiForgeryInputTag == removedStart || removedStart == tokenValue)
        throw new InvalidOperationException("Oops! The Html.AntiForgeryToken() method seems to return something I did not expect.");
    return new MvcHtmlString(string.Format(@"{0}:""{1}""", "__RequestVerificationToken", tokenValue));
}

, который вернет строку

__RequestVerificationToken:"P5g2D8vRyE3aBn7qQKfVVVAsQc853s-naENvpUAPZLipuw0pa_ffBf9cINzFgIRPwsf7Ykjt46ttJy5ox5r3mzpqvmgNYdnKc1125jphQV0NnM5nGFtcXXqoY3RpusTH_WcHPzH4S4l1PmB8Uu7ubZBftqFdxCLC5n-xT0fHcAY1"

, поэтому мы можем использовать его следующим образом

$(function () {
    $("#submit-list").click(function () {
        $.ajax({
            url: '@Url.Action("SortDataSourceLibraries")',
            data: { items: $(".sortable").sortable('toArray'), @Html.AntiForgeryTokenForAjaxPost() },
            type: 'post',
            traditional: true
        });
    });
});

И это работает!

  • 5
    +1, приятно. Я просто разделил @Html.AntiForgeryTokenForAjaxPost на две части, чтобы получить имя токена в одной руке и его значение в другой. Иначе подсветка синтаксиса все испортила. Это заканчивается так (убрал одинарные кавычки из возвращаемого результата, так что он ведет себя как любой помощник MVC, например, @Url): '@Html.AntiForgeryTokenName' : '@Html.AntiForgeryTokenValue'
  • 3
    Ницца хороша. С этим у вас есть ajax вызов файла cshtm .... вы не должны mox js с бритвой так много, по моему мнению.
Показать ещё 4 комментария
22

Это так просто! когда вы используете @Html.AntiForgeryToken() в своем html-коде, это означает, что сервер подписал эту страницу, и каждый запрос, отправленный на сервер с этой конкретной страницы, имеет знак, которому запрещено отправлять фальшивый запрос хакерами. поэтому для аутентификации этой страницы сервером вы должны пройти два этапа:

1.send параметр с именем __RequestVerificationToken и для получения его значений используйте коды ниже:

<script type="text/javascript">
    function gettoken() {
        var token = '@Html.AntiForgeryToken()';
        token = $(token).val();
        return token;
   }
</script>

например, выполните вызов ajax

$.ajax({
    type: "POST",
    url: "/Account/Login",
    data: {
        __RequestVerificationToken: gettoken(),
        uname: uname,
        pass: pass
    },
    dataType: 'json',
    contentType: 'application/x-www-form-urlencoded; charset=utf-8',
    success: successFu,
});

и шаг 2 просто украсить ваш метод действий [ValidateAntiForgeryToken]

  • 0
    Спасибо, отлично работает для json post ... мне не хватало contentType :(
4


        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 "";
            }
        }
2

Я знаю, что это старый вопрос. Но я все равно добавлю свой ответ, может помочь кому-то вроде меня.

Если вы не хотите обрабатывать результат после действия контроллера, например вызов метода LoggOff контроллера Accounts, вы можете сделать следующую версию ответа @DarinDimitrov:

@using (Html.BeginForm("LoggOff", "Accounts", FormMethod.Post, new { id = "__AjaxAntiForgeryForm" }))
{
    @Html.AntiForgeryToken()
}

<!-- this could be a button -->
<a href="#" id="ajaxSubmit">Submit</a>

<script type="text/javascript">
    $('#ajaxSubmit').click(function () {

        $('#__AjaxAntiForgeryForm').submit();

        return false;
    });
</script>
0

В Asp.Net MVC при использовании @Html.AntiForgeryToken() Razor создает скрытое поле ввода с именем __RequestVerificationToken для хранения токенов. Если вы хотите написать реализацию AJAX, вы должны сами получить этот токен и передать его в качестве параметра на сервер, чтобы его можно было проверить.

Шаг 1: Получить маркер

var token = $('input[name="`__RequestVerificationToken`"]').val();

Шаг 2: Передайте токен в вызове AJAX

function registerStudent() {

var student = {     
    "FirstName": $('#fName').val(),
    "LastName": $('#lName').val(),
    "Email": $('#email').val(),
    "Phone": $('#phone').val(),
};

$.ajax({
    url: '/Student/RegisterStudent',
    type: 'POST',
    data: { 
     __RequestVerificationToken:token,
     student: student,
        },
    dataType: 'JSON',
    contentType:'application/x-www-form-urlencoded; charset=utf-8',
    success: function (response) {
        if (response.result == "Success") {
            alert('Student Registered Succesfully!')

        }
    },
    error: function (x,h,r) {
        alert('Something went wrong')
      }
})
};

Примечание. Тип контента должен быть 'application/x-www-form-urlencoded; charset=utf-8'

Я загрузил проект в Github; вы можете скачать и попробовать.

https://github.com/lambda2016/AjaxValidateAntiForgeryToken

  • 0
    Как я могу использовать форму сериализации здесь студент: $ ('# frm-student'). Serialize (),
0

Я пробовал много рабочих мест, и не они работали для меня. Исключением было "Необходимое поле формы подделки" __RequestVerificationToken.

Что помогло мне в том, чтобы сменить форму .ajax на .post:

$.post(
    url,
    $(formId).serialize(),
    function (data) {
        $(formId).html(data);
    });

Ещё вопросы

Сообщество Overcoder
Наверх
Меню