incluir antiforgerytoken en ajax post ASP.NET MVC

Tengo problemas con AntiForgeryToken con ajax. Estoy usando ASP.NET MVC 3. Probé la solución en llamadas jQuery Ajax y Html.AntiForgeryToken (). Usando esa solución, ahora se pasa el token:

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

Cuando quito el [ValidateAntiForgeryToken] atributo solo para ver si los datos (con el token) se pasan como parámetros al controlador, puedo ver que se están pasando. Pero por alguna razón, el A required anti-forgery token was not supplied or was invalid. el mensaje sigue apareciendo cuando vuelvo a colocar el atributo.

¿Alguna idea?

EDITAR

El token antifalsificación se genera dentro de un formulario, pero no estoy usando una acción de envío para enviarlo. En cambio, solo obtengo el valor del token usando jquery y luego trato de publicarlo con ajax.

Este es el formulario que contiene el token y se encuentra en la página maestra superior:

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

preguntado el 23 de enero de 13 a las 06:01

13 Respuestas

Ha especificado incorrectamente el contentType a application/json.

He aquí un ejemplo de cómo podría funcionar esto.

Controlador:

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

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

Vista

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

Respondido el 23 de enero de 13 a las 06:01

Hola, gracias por la rápida respuesta. Lo siento, no lo mencioné en la pregunta; No estoy usando la acción de envío en este momento. (El token está en un formulario, pero no estoy usando un botón de envío para enviarlo). ¿Es posible simplemente cambiar el tipo de contenido a otra cosa? - DO Raqueño

El hecho de que no esté utilizando una acción de envío no cambia mucho mi respuesta. Todo lo que necesita hacer es suscribirse a algún otro evento (un clic de botón, un clic de ancla o lo que sea y simplemente leer el valor del campo oculto). En lo que respecta al envío de la solicitud AJAX, podría usar el ejemplo proporcionado en mi respuesta. no debes usar contentType a application/json porque el servidor está esperando el __RequestVerificationToken parámetro para ser parte de la carga útil de la solicitud POST usando application/x-www-form-urlencoded. - darin dimitrov

como este codigo $(this).data('url'), puedo entender cuál sería la url de mi controlador y acción. por favor explique. Gracias - Mou

La pregunta original era sobre contentType: 'application/json'. Para las publicaciones regulares de ajax, incluir el __RequestVerificationToken en la publicación del formulario obviamente funcionará porque es como una publicación de formulario regular. Sin embargo, cuando desea publicar json (de ahí el tipo de contenido), esto no parece funcionar. Entonces, este es un caso de aceptar incorrectamente lo anterior como respuesta. - John

¿Necesito usar "ModelState.IsValid"? ¿Cómo puedo saber que esto está funcionando? - Morán Monovich

Otra El enfoque (menos javascriptish), que hice, es algo como esto:

Primero, un ayudante 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));
}

que devolverá una cadena

__RequestVerificationToken:"P5g2D8vRyE3aBn7qQKfVVVAsQc853s-naENvpUAPZLipuw0pa_ffBf9cINzFgIRPwsf7Ykjt46ttJy5ox5r3mzpqvmgNYdnKc1125jphQV0NnM5nGFtcXXqoY3RpusTH_WcHPzH4S4l1PmB8Uu7ubZBftqFdxCLC5n-xT0fHcAY1"

entonces podemos usarlo así

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

¡Y parece funcionar!

Respondido 17 Abr '13, 11:04

+1, bueno. Acabo de dividir el @Html.AntiForgeryTokenForAjaxPost en dos para obtener el nombre del token en una mano y su valor en la otra. De lo contrario, el resaltado de sintaxis está en mal estado. Termina así (también se eliminaron las comillas simples del resultado devuelto, para que se comporte como cualquier ayudante de MVC, por ejemplo, @Url): '@Html.AntiForgeryTokenName' : '@Html.AntiForgeryTokenValue' - Askolein

nit agradable. Con esto Tienes un archivo ajax call n cshtm.... en mi opinión, no deberías mox js con razor tanto. - bunny1985

He rechazado esta pregunta porque creo que un enfoque más simple es usar la clase estática AntiForgery. Obtener HTML y reemplazarlo en lugar de obtener directamente el valor del token es una mala práctica. ASP.NET es completamente de código abierto: github.com/ASP-NET-MVC/aspnetwebstack/blob/… (pero ahora podría valer la pena escribir otra respuesta con un método de extensión personalizado que solo obtenga el token) - usr-local-ΕΨΗΕΛΩΝ

Una forma más limpia de obtener solo el valor del token sería usar XElement. XElement.Parse(antiForgeryInputTag).Attribute("value").Value - darrunategui

@transformador var antiForgeryInputTag = helper.AntiForgeryToken().ToString(); return XElement.Parse(antiForgeryInputTag).Attribute("value").Value - darrunategui

es tan simple! cuando usas @Html.AntiForgeryToken() en su código html significa que el servidor ha firmado esta página y cada solicitud que se envía al servidor desde esta página en particular tiene una señal que impide que los piratas informáticos envíen una solicitud falsa. por lo tanto, para que el servidor autentique esta página, debe realizar dos pasos:

1.enviar un parámetro llamado __RequestVerificationToken y para obtener su valor use los siguientes códigos:

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

por ejemplo tomar una llamada 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,
});

y el paso 2 simplemente decora tu método de acción [ValidateAntiForgeryToken]

Respondido 16 Abr '16, 16:04

Gracias, funciona muy bien para json post... me faltaba contentType :( - Snziv Gupta

Gracias. Buena idea con el uso $(htmlWithInputString).val() para obtener ficha. Lo hice con atributo de datos (para evitar scripts en línea en html). Algo como esto <div class="js-html-anti-forgery-token" data-anti-forgery-token-html-input="@(Html.AntiForgeryToken().ToString())"> en HTML y $($(".js-html-anti-forgery-token").data("antiForgeryTokenHtmlInput")).val() en JS. - Mariusz Pawelski

En Asp.Net Core puede solicitar el token directamente, como se documenta:

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

Y úsalo en javascript:

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

Puede agregar el filtro global recomendado, como se documenta:

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

Noticias

La solución anterior funciona en scripts que forman parte de .cshtml. Si este no es el caso, entonces no puede usar esto directamente. Mi solución fue usar un campo oculto para almacenar el valor primero.

Mi solución alternativa, todavía usando GetAntiXsrfRequestToken:

Cuando no hay forma:

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

El name El atributo se puede omitir ya que uso el id atributo.

cada formulario incluye este token. Entonces, en lugar de agregar otra copia del mismo token en un campo oculto, también puede buscar un campo existente por name. Tenga en cuenta: puede haber varios formularios dentro de un documento, por lo que name en ese caso no es único. A diferencia de un id atribuir eso debemos ser único.

En el script, busque por id:

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

Una alternativa, sin tener que hacer referencia al token, es enviar el formulario con el script.

Forma de muestra:

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

El token se agrega automáticamente al formulario como un campo oculto:

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

Y enviar en el script:

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

O usando un método de publicación:

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

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

Respondido 14 Feb 20, 21:02

Creo que esta solución solo funciona si su javascript también está en su archivo cshtml. - carlin.scott

En Asp.Net MVC cuando usa @Html.AntiForgeryToken() Razor crea un campo de entrada oculto con nombre __RequestVerificationToken para almacenar fichas. Si desea escribir una implementación de AJAX, debe obtener este token usted mismo y pasarlo como parámetro al servidor para que pueda validarse.

Paso 1: Obtener el token

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

Paso 2: Pase el token en la llamada 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')
      }
})
};

Nota:: El tipo de contenido debe ser 'application/x-www-form-urlencoded; charset=utf-8'

He subido el proyecto en Github; Puedes descargarlo y probarlo.

https://github.com/lambda2016/AjaxValidateAntiForgeryToken

Respondido 20 Jul 16, 20:07

¿Cómo puedo usar el formulario serializar aquí estudiante: $('#frm-student').serialize(), - Pequeño dragón

        function DeletePersonal(id) { var data = new FormData(); data.append("__RequestVerificationToken", "@HtmlHelper.GetAntiForgeryToken()"); $.ajax({ tipo: 'POST', url: '/Personal/Eliminar/' + id, datos: datos, caché: falso, datos de proceso: falso, tipo de contenido: falso, éxito: función (resultado) { } }); } clase estática pública HtmlHelper { cadena estática pública GetAntiForgeryToken() { System.Text.RegularExpressions.Match value = System.Text.RegularExpressions.Regex.Match(System.Web.Helpers.AntiForgery.GetHtml().ToString(), "( ?:valor=\")(.*)(?:\")"); if (valor.Éxito) { valor de retorno.Grupos[1].Valor; } devolver ""; } }

Respondido el 01 de Septiembre de 16 a las 19:09

En el controlador de cuentas:

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

En vista:

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

Es importante establecer contentType a 'application/x-www-form-urlencoded; charset=utf-8' o simplemente omitir contentTypedel objeto...

respondido 09 nov., 18:18

no es realmente práctico, significa que tiene que codificar cada formulario, y si los formularios tienen muchos elementos, podría ser una molestia :( - djack109

Sé que esta es una vieja pregunta. Pero agregaré mi respuesta de todos modos, podría ayudar a alguien como yo.

Si no desea procesar el resultado de la acción posterior del controlador, como llamar al LoggOff método de Accounts controlador, podría hacer la siguiente versión de la respuesta de @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>

Respondido el 27 de junio de 15 a las 22:06

El token no funcionará si lo suministró un controlador diferente. Por ejemplo, no funcionará si la vista fue devuelta por el Accounts controlador, pero usted POST En el correo electrónico “Su Cuenta de Usuario en su Nuevo Sistema XNUMXCX”. Clients controlador.

Respondido 13 ago 19, 10:08

Probé muchas soluciones y ninguna funcionó para mí. La excepción fue "El campo de formulario antifalsificación requerido "__RequestVerificationToken" .

Lo que me ayudó fue cambiar de .ajax a .post:

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

Respondido 19 Jul 16, 16:07

Siéntase libre de usar la siguiente función:

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

}

Respondido el 19 de Septiembre de 18 a las 17:09

Cree un método que será responsable de agregar token

var addAntiForgeryToken = function (data) {
    data.__RequestVerificationToken = $("[name='__RequestVerificationToken']").val();
    return data;
};

Ahora use este método mientras pasa datos/parámetros a Acción como se muestra a continuación

 var Query = $("#Query").val();
        $.ajax({
            url: '@Url.Action("GetData", "DataCheck")',
            type: "POST",
            data: addAntiForgeryToken({ Query: Query }),
            dataType: 'JSON',
            success: function (data) {
            if (data.message == "Success") {
            $('#itemtable').html(data.List);
            return false;
            }
            },
            error: function (xhr) {
            $.notify({
            message: 'Error',
            status: 'danger',
            pos: 'bottom-right'
            });
            }
            });

Aquí mi Acción tiene un solo parámetro de tipo cadena

    [HttpPost]
    [ValidateAntiForgeryToken]
    public JsonResult GetData( string Query)
    {

Respondido 11 ago 21, 07:08

 @using (Ajax.BeginForm("SendInvitation", "Profile",
        new AjaxOptions { HttpMethod = "POST", OnSuccess = "SendInvitationFn" },
        new { @class = "form-horizontal", id = "invitation-form" }))
    {
        @Html.AntiForgeryToken()
        <span class="red" id="invitation-result">@Html.ValidationSummary()</span>

        <div class="modal-body">
            <div class="row-fluid marg-b-15">
                <label class="block">                        
                </label>
                <input type="text" id="EmailTo" name="EmailTo" placeholder="forExample@gmail.com" value="" />
            </div>
        </div>

        <div class="modal-footer right">
            <div class="row-fluid">
                <button type="submit" class="btn btn-changepass-new">send</button>
            </div>
        </div>
    }

respondido 17 nov., 21:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.