J'utilise JQuery avec ASP.NET Core 1.0.1 et j'ai l'appel Ajax:
$("#send-message").on("submit", function (event) {
event.preventDefault();
var $form = $(this);
$.ajax({
url: "api/messages",
data: JSON.stringify($form.serializeToJSON()),
dataType: "json",
headers: {
Accept: "application/json",
"Content-Type": "application/json"
},
type: "post"
})
.done(function (data, status, xhr) { })
.fail(function (xhr, status, error) { });
Pour l'action ASP.NET Core:
[HttpPost("messages")]
public async Task<IActionResult> Post([FromBody]MessagePostApiModelModel model) {
// Send message
}
Le formulaire est dans une vue partagée et se présente comme suit:
<form id="send-question" method="post">
<textarea name="content"></textarea>
<button class="button" type="submit">Enviar</button>
</form>
Lorsque je soumets le formulaire, le message d'erreur s'affiche:
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The required antiforgery header value "RequestVerificationToken" is not present.
Comment puis-je activer AntiForgeryToken d'ASP.NET Core avec les appels JQuery Ajax?
METTRE &AGRAVE; JOUR
J'ai besoin d'ajouter l'asp-controller et l'asp-action suivants au formulaire:
<form asp-controller="QuestionApi" asp-action="Post" id="send-question" method="post">
</form>
Cela générera le jeton antiforgery. Et je devais ajouter manuellement le jeton aux en-têtes de l'appel JQuery comme suit:
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
"RequestVerificationToken": $form.find("input[name='af_token']").val()
},
Y a-t-il une meilleure manière de faire cela?
Comment résoudre ce problème quand il n'y a pas de formulaire et que je n'ai qu'un tag A qui, lorsqu'il est cliqué, appelle Ajax? Puis-je générer un jeton antiforgery commun sur l'en-tête de page à utiliser par tous les appels ajax de cette page?
la réponse de mode777 nécessite juste un petit ajout pour que cela fonctionne (je l'ai essayé):
$(document).ajaxSend(function(e, xhr, options) {
if (options.type.toUpperCase() == "POST") {
var token = $form.find("input[name='af_token']").val();
xhr.setRequestHeader("RequestVerificationToken", token);
}
});
En fait, si vous soumettez également en utilisant Ajax, vous n'avez pas du tout besoin d'utiliser de formulaire ..__ Mettez ceci dans votre _layout:
<span class="AntiForge"> @Html.AntiForgeryToken() </span>
Ensuite, vous récupérez le jeton en l'ajoutant à votre javascript:
$(document)
.ajaxSend(function (event, jqxhr, settings) {
if (settings.type.toUpperCase() != "POST") return;
jqxhr.setRequestHeader('RequestVerificationToken', $(".AntiForge" + " input").val())
})
@HtmlAntiForgeryToken génère un champ de saisie masqué avec le jeton antiforgery, identique à celui utilisé lors de l'utilisation d'un formulaire. Le code ci-dessus le trouve en utilisant le sélecteur de classe pour sélectionner la plage, puis obtient le champ de saisie à l'intérieur de celui-ci pour collecter le jeton et l'ajouter en tant qu'en-tête.
Remarque: cette réponse s'applique à ASP.NET Core 2.0. Cela peut ne pas convenir aux anciennes versions.
Voici ce que j'ai fait après avoir fouillé dans le code source d'aspnet pendant un court instant:
public static class HttpContextExtensions
{
public static string GetAntiforgeryToken(this HttpContext httpContext)
{
var antiforgery = (IAntiforgery)httpContext.RequestServices.GetService(typeof(IAntiforgery));
var tokenSet = antiforgery.GetAndStoreTokens(httpContext);
string fieldName = tokenSet.FormFieldName;
string requestToken = tokenSet.RequestToken;
return requestToken;
}
}
Vous pouvez l'utiliser dans une vue comme celle-ci:
<script>
var data = {
yourData: "bla",
"__RequestVerificationToken": "@Context.GetAntiforgeryToken()"
};
$.post("@Url.Action("ActionName")", data);
</script>
Vous pouvez modifier la méthode d'extension pour renvoyer également le nom du champ, sous la forme de votre choix, e. g. un fragment JSON.
Vous pouvez enregistrer un événement global ajax qui ajoutera l'en-tête à tous les appels ajax qui ne sont pas GET par ceci:
$(document).ajaxSend(function(e, xhr, options) {
if (options.type.toUpperCase() != "GET") {
xhr.setRequestHeader("RequestVerificationToken", token);
}
});
Dans Asp.Net Core, vous pouvez demander le jeton directement, comme documenté :
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
Et utilisez-le en javascript:
function DoSomething(id) {
$.post("/something/todo/"+id,
{ "__RequestVerificationToken": '@GetAntiXsrfRequestToken()' });
}
Vous pouvez ajouter le filtre global recommandé, comme documenté :
services.AddMvc(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
})
En plus de ygoe's answer , si vous souhaitez transmettre un jeton XSRF en tant qu'en-tête, par exemple X-XSRF-Token
:
var ajax = {
url: "/users",
data: data,
type: "post",
// ...
};
var antiForgeryToken = $("input[name=__RequestVerificationToken]").val();
if (antiForgeryToken) {
ajax.headers = {};
ajax.headers["X-XSRF-Token"] = antiForgeryToken;
};
$.ajax(ajax);
alors vous devrez également spécifier l'option antiforgery respective:
public void ConfigureServices(IServiceCollection services)
{
// your services to inject are also configured here ...
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-Token");
services.AddMvc();
}
Vous pouvez ensuite utiliser l'attribut standard ValidateAntiForgeryToken
pour valider la demande:
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult Users(UserModel user)
{
// ...
}