ASP.NET MVC ajax sonrası antiforgerytoken dahil


168

Ajax ile konuşulan AntiForgeryToken ile sorun yaşıyorum. ASP.NET MVC 3 kullanıyorum. JQuery Ajax çağrıları ve Html.AntiForgeryToken () çözümü denedim . Bu çözümü kullanarak, belirteç şimdi geçiyor:

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]Verileri (jetonla) denetleyiciye parametre olarak iletilip iletilmediğini görmek için özniteliği kaldırdığımda, bunların iletildiğini görebiliyorum. Ancak bir nedenden dolayı, A required anti-forgery token was not supplied or was invalid.özniteliği geri koyduğumda mesaj hala açılıyor.

Herhangi bir fikir?

DÜZENLE

Antiforgerytoken bir form içinde oluşturuluyor, ancak göndermek için bir gönderme eylemi kullanmıyorum. Bunun yerine, jquery kullanarak jetonun değerini alıyorum ve daha sonra bunu yayınlamaya çalışıyorum.

Belirteci içeren ve üst kalıp sayfada yer alan form:

<form id="__AjaxAntiForgeryForm" action="#" method="post">
    @Html.AntiForgeryToken()
</form>

Yanıtlar:


289

Yanlış belirtmiş contentTypeiçin application/json.

İşte bunun nasıl çalışabileceğine dair bir örnek.

Denetleyici:

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

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

Görünüm:

@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>

Merhaba, hızlı cevap için teşekkürler. Üzgünüm soruda bahsetmedim; Şu anda gönderme işlemini kullanmıyorum. (Simge bir formda, ancak göndermek için bir gönderme düğmesi kullanmıyorum). Sadece içerik türünü başka bir şeyle değiştirmek mümkün müdür?
OJ Raqueño

13
Bir gönderme işlemi kullanmamanız cevabımı pek değiştirmez. Tek yapmanız gereken başka bir etkinliğe abone olmaktır (bir düğme tıklaması, bir çapa tıklaması veya herhangi bir şey ve sadece gizli alan değerini okuyun). AJAX isteği göndermek söz konusu olduğunda, cevabımda verilen örneği kullanabilirsiniz. Sen kullanmamalısınız contentTypeiçin application/jsonsunucu bekliyor çünkü __RequestVerificationTokenparametre kullanarak POST isteği bilgisi parçası olmak application/x-www-form-urlencoded.
Darin Dimitrov

bu kodun $(this).data('url'),denetleyicimin ve eylemimin URL'sinin ne olacağını nasıl anlayabildiğini. lütfen açıkla. teşekkürler
Mou

2
Orijinal soru contentType: 'application / json' hakkındaydı. Form gönderisindeki __RequestVerificationToken dahil olmak üzere normal ajax gönderileri için, normal bir biçim gönderisi gibi olduğu için açıkça çalışacaktır. Ancak json yayınlamak istediğinizde (dolayısıyla içerik türü) bu işe yaramıyor gibi görünüyor. Bu, yukarıdakileri yanlış bir cevap olarak kabul etme durumudur.
John

"ModelState.IsValid" kullanmam gerekir mi? Bunun işe yaradığını nasıl anlayabilirim?
Moran Monovich

61

Yaptığım başka bir (daha az javascript) yaklaşım, böyle bir şey gider:

İlk olarak, bir Html yardımcısı

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));
}

bir dize döndürecek

__RequestVerificationToken:"P5g2D8vRyE3aBn7qQKfVVVAsQc853s-naENvpUAPZLipuw0pa_ffBf9cINzFgIRPwsf7Ykjt46ttJy5ox5r3mzpqvmgNYdnKc1125jphQV0NnM5nGFtcXXqoY3RpusTH_WcHPzH4S4l1PmB8Uu7ubZBftqFdxCLC5n-xT0fHcAY1"

böylece bu şekilde kullanabiliriz

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

Ve işe yarıyor gibi görünüyor!


5
+1, güzel. @Html.AntiForgeryTokenForAjaxPostBir elinde jeton adını ve diğer elinde değerini almak için ikiye böldüm. Aksi takdirde sözdizimi vurgulaması tamamen bozulur. Bu şekilde sona erer (döndürülen sonuçtan tek tırnaklar da kaldırılır, böylece herhangi bir MVC yardımcısı gibi davranır, örneğin @Url):'@Html.AntiForgeryTokenName' : '@Html.AntiForgeryTokenValue'
Askolein

4
çok güzel. Bu ile ajax çağrı n cshtm dosya var .... benim görüşüme göre jilet js mox olmamalıdır.
bunny1985

Bu soruyu reddettim çünkü daha basit bir yaklaşımın AntiForgery statik sınıfını kullanmak olduğuna inanıyorum. Doğrudan jeton değerini almak yerine HTML almak ve değiştirmek kötü bir uygulamadır. ASP.NET tamamen açık kaynak: github.com/ASP-NET-MVC/aspnetwebstack/blob/… (ancak şimdi yalnızca jetonu alan özel bir uzantı yöntemiyle başka bir yanıt yazmaya değer olabilir)
usr-local- ΕΨΗΕΛΩΝ

4
Sadece jeton değerini elde etmenin daha temiz bir yolu XElement kullanmak olacaktır. XElement.Parse(antiForgeryInputTag).Attribute("value").Value
darrunategui

3
@transformervar antiForgeryInputTag = helper.AntiForgeryToken().ToString(); return XElement.Parse(antiForgeryInputTag).Attribute("value").Value
darrunategui

45

çok basit! @Html.AntiForgeryToken()html kodunuzda kullandığınızda , sunucu bu sayfayı imzalamış demektir ve bu belirli sayfadan sunucuya gönderilen her istek, bilgisayar korsanları tarafından sahte bir istek gönderilmesini engelleyen bir işarete sahiptir. bu nedenle bu sayfanın sunucu tarafından doğrulanması için iki adımdan geçmeniz gerekir:

1. adlı bir parametre __RequestVerificationTokengönderin ve değerini aşağıdaki kodları kullanın:

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

örneğin ajax araması yapın

$.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,
});

ve 2. adım sadece eylem yönteminizi [ValidateAntiForgeryToken]


Teşekkürler, json post için harika çalışıyor ... i
içerik eksiktiType

9

Asp.Net Çekirdek size doğrudan belirteci isteyebilir belgelendiği gibi :

@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf    
@functions{
    public string GetAntiXsrfRequestToken()
    {
        return Xsrf.GetAndStoreTokens(Context).RequestToken;
    }
}

Ve javascript ile kullanın:

function DoSomething(id) {
    $.post("/something/todo/"+id,
               { "__RequestVerificationToken": '@GetAntiXsrfRequestToken()' });
}

Önerilen genel filtreyi belgelendiği gibi ekleyebilirsiniz :

services.AddMvc(options =>
{
    options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
})

Güncelleme

Yukarıdaki çözüm .cshtml dosyasının bir parçası olan komut dosyalarında çalışır. Eğer durum böyle değilse, bunu doğrudan kullanamazsınız. Benim çözümüm önce değeri saklamak için gizli bir alan kullanmaktı.

Geçici çözümüm hala kullanılıyor GetAntiXsrfRequestToken:

Form olmadığında:

<input type="hidden" id="RequestVerificationToken" value="@GetAntiXsrfRequestToken()">

nameKullandığım beri nitelik atlanabilir idniteliği.

Her form bu belirteci içerir. Dolayısıyla, gizli bir alana aynı belirtecin başka bir kopyasını eklemek yerine, tarafından mevcut bir alanı da arayabilirsiniz name. Lütfen dikkat: bir belgenin içinde birden çok form olabilir, bu nedenle namebu benzersiz değildir. Benzersiz olması gereken bir idözellikten farklı olarak.

Kodda kimliğe göre bulun:

function DoSomething(id) {
    $.post("/something/todo/"+id,
       { "__RequestVerificationToken": $('#RequestVerificationToken').val() });
}

Alternatif, jetona başvurmak zorunda kalmadan, formu komut dosyasıyla göndermektir.

Örnek form:

<form id="my_form" action="/something/todo/create" method="post">
</form>

Simge forma otomatik olarak gizli bir alan olarak eklenir:

<form id="my_form" action="/something/todo/create" method="post">
<input name="__RequestVerificationToken" type="hidden" value="Cf..." /></form>

Ve senaryoda gönderin:

function DoSomething() {
    $('#my_form').submit();
}

Veya bir posta yöntemi kullanarak:

function DoSomething() {
    var form = $('#my_form');

    $.post("/something/todo/create", form.serialize());
}

Bu çözüm sadece javascript cshtml dosyasında ise çalışır düşünüyorum.
carlin.scott

6

Asp.Net MVC @Html.AntiForgeryToken()Razor kullandığınızda __RequestVerificationTokenbelirteçleri depolamak için ad ile gizli bir giriş alanı oluşturur . Bir AJAX uygulaması yazmak istiyorsanız, bu jetonu kendiniz getirmeniz ve doğrulanabilmesi için bir parametre olarak sunucuya iletmeniz gerekir.

1. Adım: Jetonu alın

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

Adım 2: Kartı AJAX çağrısında geçirin

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')
      }
})
};

Not : İçerik türü'application/x-www-form-urlencoded; charset=utf-8'

Projeyi Github'a yükledim; indirip deneyebilirsiniz.

https://github.com/lambda2016/AjaxValidateAntiForgeryToken



6

        işlev DeletePersonel (id) {

                var data = yeni FormData ();
                data.append ("__ RequestVerificationToken", "@ HtmlHelper.GetAntiForgeryToken ()");

                {(.Ajax, $
                    şunu yazın: 'POST',
                    url: '/ Personel / Sil /' + kimlik,
                    veri: veri,
                    önbellek: yanlış,
                    processData: yanlış,
                    contentType: false,
                    success: function (sonuç) {

                    }
                });

        }
    

        genel statik sınıf HtmlHelper
        {
            genel statik dize GetAntiForgeryToken ()
            {
                System.Text.RegularExpressions.Match value = System.Text.RegularExpressions.Regex.Match (System.Web.Helpers.AntiForgery.GetHtml (). ToString (), "(?: Değer = \") (. *) (? : \ ")");
                eğer (value.Success)
                {
                    dönüş değeri.Gruplar [1] .Değer;
                }
                dönüş "";
            }
        }

3

Bunun eski bir soru olduğunu biliyorum. Ama yine de cevabımı ekleyeceğim, benim gibi birine yardım edebilirim.

Sonucu LoggOff, Accountsdenetleyici yöntemini çağırmak gibi denetleyicinin gönderdiği eylemden işlemek istemiyorsanız , @DarinDimitrov'un yanıtının aşağıdaki sürümü olarak yapabilirsiniz:

@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>

3

Hesap denetleyicisinde:

    // POST: /Account/SendVerificationCodeSMS
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public JsonResult SendVerificationCodeSMS(string PhoneNumber)
    {
        return Json(PhoneNumber);
    }

Görünümünde:

$.ajax(
{
    url: "/Account/SendVerificationCodeSMS",
    method: "POST",
    contentType: 'application/x-www-form-urlencoded; charset=utf-8',
    dataType: "json",
    data: {
        PhoneNumber: $('[name="PhoneNumber"]').val(),
        __RequestVerificationToken: $('[name="__RequestVerificationToken"]').val()
    },
    success: function (data, textStatus, jqXHR) {
        if (textStatus == "success") {
            alert(data);
            // Do something on page
        }
        else {
            // Do something on page
        }
    },
    error: function (jqXHR, textStatus, errorThrown) {
        console.log(textStatus);
        console.log(jqXHR.status);
        console.log(jqXHR.statusText);
        console.log(jqXHR.responseText);
    }
});

Bu sette önemlidir contentTypeetmek 'application/x-www-form-urlencoded; charset=utf-8'ya da sadece ihmal contentTypenesneden ...


gerçekten pratik değil, her formu kodlamanız gerektiği anlamına gelir ve formların çok sayıda öğesi varsa bir acı olabilir :(
djack109

0

Bir sürü çalışma denedim ve hiçbiri benim için çalıştı. İstisna "Zorunlu sahtecilik form alanı" __RequestVerificationToken idi.

Bana yardımcı olan şey .ajax'ı .post'a değiştirmekti:

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

0

Aşağıdaki işlevi kullanmaktan çekinmeyin:

function AjaxPostWithAntiForgeryToken(destinationUrl, successCallback) {
var token = $('input[name="__RequestVerificationToken"]').val();
var headers = {};
headers["__RequestVerificationToken"] = token;
$.ajax({
    type: "POST",
    url: destinationUrl,
    data: { __RequestVerificationToken: token }, // Your other data will go here
    dataType: "json",
    success: function (response) {
        successCallback(response);
    },
    error: function (xhr, status, error) {
       // handle failure
    }
});

}


0

Farklı bir denetleyici tarafından sağlanmışsa jeton çalışmaz. Örneğin bu görünüm tarafından döndürülen eğer çalışmaz AccountsEğer denetleyici, ama POSThiç Clientsdenetleyici.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.