अजाक्स पोस्ट ASP.NET MVC में एंटीफॉर्गीटोकन शामिल करें


167

मैं ajax के साथ antiForgeryToken को लेकर परेशान हूं। मैं 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.जब मैं विशेषता वापस डालता हूं तब भी संदेश पॉप-अप होता रहता है।

कोई विचार?

संपादित करें

एंटीफॉरगेरीटोकेन एक फॉर्म के अंदर उत्पन्न हो रहा है, लेकिन मैं इसे सबमिट करने के लिए सबमिट एक्शन का उपयोग नहीं कर रहा हूं। इसके बजाय, मैं सिर्फ jquery का उपयोग कर टोकन मूल्य प्राप्त कर रहा हूं और फिर ajax पोस्ट करने की कोशिश कर रहा हूं।

यहां वह फ़ॉर्म है जिसमें टोकन शामिल है, और शीर्ष मास्टर पृष्ठ पर स्थित है:

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

जवाबों:


288

आप गलत तरीके से निर्दिष्ट किया है 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>

नमस्कार, जल्दी जवाब देने के लिए धन्यवाद। क्षमा करें, मैंने प्रश्न में इसका उल्लेख नहीं किया है; मैं इस समय सबमिट कार्रवाई का उपयोग नहीं कर रहा / रही हूं। (टोकन एक फॉर्म में है, लेकिन मैं इसे सबमिट करने के लिए सबमिट बटन का उपयोग नहीं कर रहा हूं)। क्या केवल सामग्री प्रकार को किसी और चीज़ में बदलना संभव है?
OJ Raqueño

13
तथ्य यह है कि आप सबमिट एक्शन का उपयोग नहीं कर रहे हैं, इससे मेरा उत्तर नहीं बदलता है। आपको बस किसी अन्य घटना (एक बटन क्लिक, एक एंकर क्लिक या जो कुछ भी और बस छिपे हुए फ़ील्ड मूल्य को पढ़ना है) की सदस्यता लेनी होगी। जहाँ तक AJAX अनुरोध भेजने का संबंध है, आप मेरे उत्तर में दिए गए उदाहरण का उपयोग कर सकते हैं। आप उपयोग नहीं करना चाहिए contentTypeकरने के लिए application/jsonहै क्योंकि सर्वर उम्मीद कर रही है __RequestVerificationTokenपैरामीटर पोस्ट अनुरोध का उपयोग कर पेलोड का हिस्सा बनने का application/x-www-form-urlencoded
डारिन दिमित्रोव

यह कोड कैसे $(this).data('url'),समझ सकता है कि मेरे नियंत्रक और कार्रवाई का यूआरएल क्या होगा। कृपया समझाएँ। धन्यवाद
Mou

2
मूल प्रश्न कंटेंट टाइप के बारे में था: 'एप्लीकेशन / जसन'। नियमित ajax पदों के लिए __RequestVerificationToken सहित फॉर्म पोस्ट में स्पष्ट रूप से काम करेगा क्योंकि यह एक नियमित फॉर्म पोस्ट की तरह है। जब आप हालांकि json पोस्ट करना चाहते हैं (इसलिए सामग्री प्रकार) यह काम नहीं करता है। तो यह गलत रूप से उपरोक्त को एक उत्तर के रूप में स्वीकार करने का मामला है।
जॉन

क्या मुझे "ModelState.IsValid" का उपयोग करने की आवश्यकता है? मैं कैसे बता सकता हूं कि यह काम कर रहा है?
मोरन मोनोविच

61

एक और (कम जावास्क्रिप्ट) दृष्टिकोण, जो मैंने किया, कुछ इस तरह से होता है:

सबसे पहले, एक एचटीएमएल सहायक

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एक हाथ में टोकन नाम और दूसरे में इसके मूल्य प्राप्त करने के लिए दो में विभाजित करता हूं । अन्यथा वाक्य रचना हाइलाइट सब गड़बड़ है। यह इस तरह समाप्त होता है (लौटे परिणाम में से एकल-उद्धरण भी हटा दिया जाता है, ताकि यह किसी भी एमवीसी सहायक की तरह व्यवहार करता है, उदाहरण के लिए @Url):'@Html.AntiForgeryTokenName' : '@Html.AntiForgeryTokenValue'
अस्कॉलिन

4
नाइट अच्छा है। इसके साथ आपके पास ajax call n cshtm file है .... आपको रेजर के साथ jox नहीं करना चाहिए, मेरे विचार से।
बनी 1985

मैंने इस प्रश्न को अस्वीकार कर दिया है क्योंकि मेरा मानना ​​है कि एंटीफॉर्जरी स्टैटिक क्लास का उपयोग करने के लिए एक सरल दृष्टिकोण है। HTML प्राप्त करना और सीधे टोकन मूल्य प्राप्त करने के बजाय इसे प्रतिस्थापित करना बुरा व्यवहार है। ASP.NET पूरी तरह से खुला स्रोत है: github.com/ASP-NET-MVC/aspnetwebstack/blob/… (लेकिन अब यह कस्टम एक्सटेंशन विधि के साथ एक और उत्तर लिखने के लायक हो सकता है जो केवल टोकन प्राप्त करता है)
usr-local- ΕΨΗΕΛΩΝ

4
सिर्फ टोकन मूल्य प्राप्त करने का एक क्लीनर तरीका XElement का उपयोग करना होगा। XElement.Parse(antiForgeryInputTag).Attribute("value").Value
darrunategui

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

45

यह बहुत आसान है! जब आप @Html.AntiForgeryToken()अपने html कोड में उपयोग करते हैं तो इसका मतलब है कि सर्वर ने इस पृष्ठ पर हस्ताक्षर किए हैं और इस विशेष पृष्ठ से सर्वर को भेजे गए प्रत्येक अनुरोध पर एक संकेत है जिसे हैकर्स द्वारा नकली अनुरोध भेजने से रोका जाता है। इसलिए इस पृष्ठ को उस सर्वर द्वारा प्रमाणित किया जाए जिसके लिए आपको दो चरणों में जाना चाहिए:

1. नामांकित एक पैरामीटर भेजें __RequestVerificationTokenऔर उसके मूल्य उपयोग कोड प्राप्त करने के लिए नीचे:

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

उदाहरण के लिए अजाक्स कॉल करें

$.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]


धन्यवाद, json पोस्ट के लिए बहुत अच्छा काम करता है ... मुझे सामग्री याद आ रही थी :(
Snziv Gupta

9

Asp.Net Core में आप सीधे दस्तावेज़ के रूप में टोकन का अनुरोध कर सकते हैं :

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

और इसका उपयोग जावास्क्रिप्ट में करें:

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

आप प्रलेखित वैश्विक फिल्टर को जोड़ सकते हैं, जैसा कि प्रलेखित है :

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

अपडेट करें

उपरोक्त समाधान उन स्क्रिप्ट में काम करता है जो .cshtml का हिस्सा हैं। अगर ऐसा नहीं है तो आप सीधे इसका उपयोग नहीं कर सकते। मेरा समाधान पहले मूल्य को संग्रहीत करने के लिए एक छिपे हुए क्षेत्र का उपयोग करना था।

मेरा वर्कअराउंड, अभी भी उपयोग कर रहा है GetAntiXsrfRequestToken:

जब कोई रूप नहीं है:

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

nameविशेषता छोड़ा जा सकता है के बाद से मैं का उपयोग idविशेषता।

प्रत्येक फॉर्म में यह टोकन शामिल है। इसलिए एक छिपे हुए फ़ील्ड में उसी टोकन की एक और प्रतिलिपि जोड़ने के बजाय, आप किसी मौजूदा फ़ील्ड को भी खोज सकते हैं name। कृपया ध्यान दें: किसी दस्तावेज़ के अंदर कई रूप हो सकते हैं, इसलिए nameयह अद्वितीय नहीं है। एक idविशेषता के विपरीत जो अद्वितीय होनी चाहिए।

स्क्रिप्ट में, आईडी द्वारा खोजें:

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

एक संदर्भ, टोकन को संदर्भित किए बिना, स्क्रिप्ट के साथ फॉर्म जमा करना है।

नमूना फार्म:

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

टोकन स्वचालित रूप से एक छिपे हुए फ़ील्ड के रूप में जोड़ा जाता है:

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

और स्क्रिप्ट में सबमिट करें:

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

या एक पोस्ट विधि का उपयोग कर:

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

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

मुझे लगता है कि यह समाधान केवल तभी काम करता है जब आपकी जावास्क्रिप्ट आपकी cshtml फ़ाइल में भी हो।
carlin.scott

6

Asp.Net MVC में जब आप @Html.AntiForgeryToken()रेजर का उपयोग करते हैं तो __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'

मैंने गीथुब पर प्रोजेक्ट अपलोड किया है; आप इसे डाउनलोड और आज़मा सकते हैं।

https://github.com/lambda2016/AjaxValidateAntiForgeryToken


मैं यहाँ छात्र किस प्रकार फार्म का उपयोग कर सकता हूँ: $ ('# छात्र-छात्र')। क्रमबद्ध करें (),
लिटिलड्रैगन

6

        समारोह DeletePersonel (आईडी) {

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

                .ajax $ ({
                    प्रकार: 'पोस्ट',
                    url: '/ कार्मिक / हटाएं /' + आईडी,
                    डेटा: डेटा,
                    कैश: गलत,
                    प्रक्रियाडेटा: गलत,
                    सामग्री प्रकार: गलत,
                    सफलता: समारोह (परिणाम) {

                    }
                });

        }
    

        सार्वजनिक स्थिर वर्ग HtmlHelper
        {
            सार्वजनिक स्थैतिक स्ट्रिंग GetAntiForgeryToken ()
            {
                System.Text.RegularExpressions.Match value = System.Text.RegularExpressions.Regex.Match (System.Web.Helpers.AntiForgery.GetHtml ()। ToString) (): "(?: Value = \") (*) (?) (?) : \ ")");
                अगर (मान। असफल)
                {
                    वापसी मान। समूह [1]। शुद्ध;
                }
                वापसी "";
            }
        }

3

मैं जानता हूं कि यह एक पुराना सवाल है। लेकिन मैं अपना जवाब किसी भी तरह जोड़ दूंगा, हो सकता है कि मेरी तरह कोई मदद करे।

यदि आप नियंत्रक की पोस्ट कार्रवाई से परिणाम को संसाधित नहीं करना चाहते हैं, जैसे नियंत्रक की 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>

3

खाता नियंत्रक में:

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

दृश्य में:

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

यह सेट contentTypeकरना महत्वपूर्ण है 'application/x-www-form-urlencoded; charset=utf-8'या contentTypeऑब्जेक्ट से बाहर आना चाहिए ...


वास्तव में व्यावहारिक नहीं है, इसका मतलब है कि आपको हर फॉर्म को कोड करना होगा, और अगर फॉर्म में बहुत सारे तत्व हैं तो यह दर्द हो सकता है :(
djack109

0

मैंने बहुत सारे वर्कअराउंड की कोशिश की और उनमें से गैर ने मेरे लिए काम किया। अपवाद था "आवश्यक एंटी-फर्जी फॉर्म फ़ील्ड" __RequestVerificationToken "।

फ़ॉर्म को स्विच करने में मुझे जो मदद मिली वह थी .ajax to .post:

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

0

नीचे दिए गए फ़ंक्शन का उपयोग करने के लिए स्वतंत्र महसूस करें:

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

यदि यह एक अलग नियंत्रक द्वारा आपूर्ति की गई थी, तो टोकन काम नहीं करेगा। उदाहरण के लिए यह करता है, तो देखने के द्वारा दिया गया था काम नहीं करेगा Accountsनियंत्रक, लेकिन आप POSTके लिए Clientsनियंत्रक।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.