Ich verwende den folgenden Code in diesem Beitrag:
Zuerst fülle ich eine Array-Variable mit den richtigen Werten für die Controller-Aktion.
Mit dem folgenden Code sollte es meiner Meinung nach sehr einfach sein, dem JavaScript-Code nur die folgende Zeile hinzuzufügen:
data["__RequestVerificationToken"] = $('[name=__RequestVerificationToken]').val();
Das <%= Html.AntiForgeryToken() %>
ist am richtigen Ort, und die Aktion hat eine[ValidateAntiForgeryToken]
Aber meine Controller-Aktion sagt immer wieder: "Ungültiger Fälschungs-Token"
Was mache ich hier falsch?
Code
data["fiscalyear"] = fiscalyear;
data["subgeography"] = $(list).parent().find('input[name=subGeography]').val();
data["territories"] = new Array();
$(items).each(function() {
data["territories"].push($(this).find('input[name=territory]').val());
});
if (url != null) {
$.ajax(
{
dataType: 'JSON',
contentType: 'application/json; charset=utf-8',
url: url,
type: 'POST',
context: document.body,
data: JSON.stringify(data),
success: function() { refresh(); }
});
}
asp.net-mvc
ajax
json
antiforgerytoken
HerbalMart
quelle
quelle
ValidateJsonAntiForgeryTokenAttribute
hingelegt?[ValidateJsonAntiForgeryToken]
auf meinerActionResult
und habe dann die JS genau so, wie Sie sie haben. Chrome Developer Tools "Netzwerk> Seitenname> Header" zeigt:__RequestVerificationToken:egrd5Iun...8AH6_t8w2
unterRequest Headers
. Was könnte sonst noch falsch sein?Was falsch ist, ist, dass die Controller-Aktion, die diese Anforderung verarbeiten soll und die mit gekennzeichnet ist,
[ValidateAntiForgeryToken]
einen Parameter erwartet, der aufgerufen wird__RequestVerificationToken
, zusammen mit der Anforderung POSTED zu werden.Es gibt keinen von Ihnen verwendeten POST-Parameter,
JSON.stringify(data)
der Ihr Formular in seine JSON-Darstellung konvertiert, und daher wird die Ausnahme ausgelöst.Daher kann ich hier zwei mögliche Lösungen sehen:
Nummer 1: Verwenden Sie
x-www-form-urlencoded
stattJSON
zum Senden Ihrer Anforderungsparameter:data["__RequestVerificationToken"] = $('[name=__RequestVerificationToken]').val(); data["fiscalyear"] = fiscalyear; // ... other data if necessary $.ajax({ url: url, type: 'POST', context: document.body, data: data, success: function() { refresh(); } });
Nummer 2: Trennen Sie die Anfrage in zwei Parameter:
data["fiscalyear"] = fiscalyear; // ... other data if necessary var token = $('[name=__RequestVerificationToken]').val(); $.ajax({ url: url, type: 'POST', context: document.body, data: { __RequestVerificationToken: token, jsonRequest: JSON.stringify(data) }, success: function() { refresh(); } });
In allen Fällen müssen Sie den
__RequestVerificationToken
Wert POSTEN .quelle
data
Variable?dataType: 'JSON'
und auchcontentType: 'application/json; charset=utf-8'
, genau wie Darin Dimitrov es in seinem Beitrag hat.Ich habe gerade dieses eigentliche Problem in meinem aktuellen Projekt implementiert. Ich habe es für alle Ajax-POSTs gemacht, die einen authentifizierten Benutzer benötigen.
Zunächst entschied ich mich, meine jQuery Ajax-Anrufe zu verknüpfen, damit ich mich nicht zu oft wiederhole. Dieses JavaScript-Snippet stellt sicher, dass alle Ajax- (Post-) Aufrufe mein Anforderungsvalidierungstoken zur Anforderung hinzufügen. Hinweis: Der Name __RequestVerificationToken wird vom .NET Framework verwendet, sodass ich die unten gezeigten Standard-Anti-CSRF-Funktionen verwenden kann.
$(document).ready(function () { securityToken = $('[name=__RequestVerificationToken]').val(); $('body').bind('ajaxSend', function (elm, xhr, s) { if (s.type == 'POST' && typeof securityToken != 'undefined') { if (s.data.length > 0) { s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken); } else { s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken); } } }); });
Verwenden Sie in Ihren Ansichten, in denen das Token für den obigen JavaScript-Code verfügbar sein muss, einfach den allgemeinen HTML-Helper. Sie können diesen Code grundsätzlich hinzufügen, wo immer Sie möchten. Ich habe es in eine if-Anweisung (Request.IsAuthenticated) eingefügt:
@Html.AntiForgeryToken() // You can provide a string as salt when needed which needs to match the one on the controller
Verwenden Sie in Ihrem Controller einfach den Standard-Anti-CSRF-Mechanismus von ASP.NET MVC. Ich habe es so gemacht (obwohl ich tatsächlich ein Salz verwendet habe).
[HttpPost] [Authorize] [ValidateAntiForgeryToken] public JsonResult SomeMethod(string param) { // Do something return Json(true); }
Mit Firebug oder einem ähnlichen Tool können Sie leicht sehen, wie an Ihre POST-Anforderungen jetzt ein __RequestVerificationToken-Parameter angehängt ist.
quelle
application/x-www-form-urlencoded
Inhaltstyp funktionieren . Das OP wollte seine Anforderungsdaten-Nutzdaten als sendenapplication/json
. Das Anhängen&__Request...
an eine JSON-Nutzlast sollte fehlschlagen. (Er bat nicht um eine JSON-Antwort, was Ihr Codebeispiel ist, sondern um eine JSON-Anfrage.)Sie können einstellen , $ Schnipsel ‚s
traditional
Attribut und setzen Sie ihn auftrue
, zu json Daten als URL kodierter Form zu senden. Stellen Sie sicher, dass Sie einstellentype:'POST'
. Mit dieser Methode können Sie sogar Arrays senden und müssen weder JSON.stringyfy noch Änderungen auf der Serverseite verwenden (z. B. benutzerdefinierte Attribute für den Sniff-Header erstellen).Ich habe dies auf ASP.NET MVC3 und jquery 1.7 Setup versucht und es funktioniert
Es folgt das Code-Snippet.
var data = { items: [1, 2, 3], someflag: true}; data.__RequestVerificationToken = $(':input[name="__RequestVerificationToken"]').val(); $.ajax({ url: 'Test/FakeAction' type: 'POST', data: data dataType: 'json', traditional: true, success: function (data, status, jqxhr) { // some code after succes }, error: function () { // alert the error } });
Dies stimmt mit der MVC-Aktion mit der folgenden Signatur überein
[HttpPost] [Authorize] [ValidateAntiForgeryToken] public ActionResult FakeAction(int[] items, bool someflag) { }
quelle
Sie können einen Inhalt vom Typ contentType nicht überprüfen: 'application / json; charset = utf-8 ', da Ihr Datum nicht in der Form- Eigenschaft der Anforderung, sondern in der InputStream-Eigenschaft hochgeladen wird und Sie diese Request.Form ["__ RequestVerificationToken"] niemals haben.
Dies ist immer leer und die Validierung schlägt fehl.
quelle
Ich halte das Token in meinem JSON-Objekt und habe am Ende die ValidateAntiForgeryToken-Klasse geändert, um den InputStream des Request- Objekts zu überprüfen, wenn der Beitrag json ist. Ich habe einen Blog-Beitrag darüber geschrieben, hoffentlich finden Sie ihn nützlich.
quelle
Sie müssen niemals ein AntiForgeryToken validieren, wenn Sie JSON erhalten.
Der Grund dafür ist, dass AntiForgeryToken erstellt wurde, um CSRF zu verhindern. Da Sie AJAX-Daten nicht auf einem anderen Host veröffentlichen können und HTML-Formulare JSON nicht als Anforderungshauptteil senden können, müssen Sie Ihre App nicht vor veröffentlichtem JSON schützen.
quelle
Ich habe es global mit RequestHeader gelöst.
$.ajaxPrefilter(function (options, originalOptions, jqXhr) { if (options.type.toUpperCase() === "POST") { // We need to add the verificationToken to all POSTs if (requestVerificationTokenVariable.length > 0) jqXhr.setRequestHeader("__RequestVerificationToken", requestVerificationTokenVariable); } });
Dabei ist requestVerificationTokenVariable eine variable Zeichenfolge, die den Tokenwert enthält. Dann senden alle Ajax-Aufrufe das Token an den Server, aber das Standard-ValidateAntiForgeryTokenAttribute erhält den Wert Request.Form. Ich habe diesen globalFilter geschrieben und hinzugefügt, der das Token vom Header in request.form kopiert, als ich das Standard-ValidateAntiForgeryTokenAttribute verwenden kann:
public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new GlobalAntiForgeryTokenAttribute(false)); } public class GlobalAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter { private readonly bool autoValidateAllPost; public GlobalAntiForgeryTokenAttribute(bool autoValidateAllPost) { this.autoValidateAllPost = autoValidateAllPost; } private const string RequestVerificationTokenKey = "__RequestVerificationToken"; public void OnAuthorization(AuthorizationContext filterContext) { var req = filterContext.HttpContext.Request; if (req.HttpMethod.ToUpperInvariant() == "POST") { //gestione per ValidateAntiForgeryToken che gestisce solo il recupero da Request.Form (non disponibile per le chiamate ajax json) if (req.Form[RequestVerificationTokenKey] == null && req.IsAjaxRequest()) { var token = req.Headers[RequestVerificationTokenKey]; if (!string.IsNullOrEmpty(token)) { req.Form.SetReadOnly(false); req.Form[RequestVerificationTokenKey] = token; req.Form.SetReadOnly(true); } } if (autoValidateAllPost) AntiForgery.Validate(); } } } public static class NameValueCollectionExtensions { private static readonly PropertyInfo NameObjectCollectionBaseIsReadOnly = typeof(NameObjectCollectionBase).GetProperty("IsReadOnly", BindingFlags.FlattenHierarchy | BindingFlags.NonPublic | BindingFlags.Instance); public static void SetReadOnly(this NameValueCollection source, bool readOnly) { NameObjectCollectionBaseIsReadOnly.SetValue(source, readOnly); } }
Diese Arbeit für mich :)
quelle
In Dixins Blog finden Sie einen großartigen Beitrag dazu.
Warum nicht auch $ .post anstelle von $ .ajax verwenden?
Zusammen mit dem jQuery-Plugin auf dieser Seite können Sie dann Folgendes tun:
data = $.appendAntiForgeryToken(data,null); $.post(url, data, function() { refresh(); }, "json");
quelle
AJAX-basiertes Modellposting mit AntiForgerytoken kann mit der Newtonsoft.JSON-Bibliothek etwas vereinfacht werden. Der folgende
Ansatz hat für mich funktioniert:
Behalten Sie Ihren AJAX-Post wie folgt bei :
$.ajax({ dataType: 'JSON', url: url, type: 'POST', context: document.body, data: { '__RequestVerificationToken': token, 'model_json': JSON.stringify(data) };, success: function() { refresh(); } });
Dann in Ihrer MVC-Aktion:
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Edit(FormCollection data) { var model = JsonConvert.DeserializeObject < Order > (data["model_json"]); return Json(1); }
Hoffe das hilft :)
quelle
Ich musste ein wenig zwielichtig sein, um Anti-Fälschungs-Token beim Posten von JSON zu validieren, aber es funktionierte.
//If it's not a GET, and the data they're sending is a string (since we already had a separate solution in place for form-encoded data), then add the verification token to the URL, if it's not already there. $.ajaxSetup({ beforeSend: function (xhr, options) { if (options.type && options.type.toLowerCase() !== 'get' && typeof (options.data) === 'string' && options.url.indexOf("?__RequestVerificationToken=") < 0 && options.url.indexOf("&__RequestVerificationToken=") < 0) { if (options.url.indexOf('?') < 0) { options.url += '?'; } else { options.url += '&'; } options.url += "__RequestVerificationToken=" + encodeURIComponent($('input[name=__RequestVerificationToken]').val()); } } });
Wie bereits erwähnt, überprüft die Validierung jedoch nur das Formular - nicht JSON und nicht die Abfragezeichenfolge. Also haben wir das Verhalten des Attributs überschrieben. Die erneute Implementierung der gesamten Validierung wäre schrecklich (und wahrscheinlich nicht sicher) gewesen. Daher habe ich die Form-Eigenschaft einfach überschrieben, um, wenn das Token im QueryString übergeben wurde, die integrierte Validierung THINK zu erhalten, die im Formular enthalten war.
Das ist etwas schwierig, da das Formular schreibgeschützt, aber machbar ist.
if (IsAuth(HttpContext.Current) && !IsGet(HttpContext.Current)) { //if the token is in the params but not the form, we sneak in our own HttpContext/HttpRequest if (HttpContext.Current.Request.Params != null && HttpContext.Current.Request.Form != null && HttpContext.Current.Request.Params["__RequestVerificationToken"] != null && HttpContext.Current.Request.Form["__RequestVerificationToken"] == null) { AntiForgery.Validate(new ValidationHttpContextWrapper(HttpContext.Current), null); } else { AntiForgery.Validate(new HttpContextWrapper(HttpContext.Current), null); } } //don't validate un-authenticated requests; anyone could do it, anyway private static bool IsAuth(HttpContext context) { return context.User != null && context.User.Identity != null && !string.IsNullOrEmpty(context.User.Identity.Name); } //only validate posts because that's what CSRF is for private static bool IsGet(HttpContext context) { return context.Request.HttpMethod.ToUpper() == "GET"; }
...
internal class ValidationHttpContextWrapper : HttpContextBase { private HttpContext _context; private ValidationHttpRequestWrapper _request; public ValidationHttpContextWrapper(HttpContext context) : base() { _context = context; _request = new ValidationHttpRequestWrapper(context.Request); } public override HttpRequestBase Request { get { return _request; } } public override IPrincipal User { get { return _context.User; } set { _context.User = value; } } } internal class ValidationHttpRequestWrapper : HttpRequestBase { private HttpRequest _request; private System.Collections.Specialized.NameValueCollection _form; public ValidationHttpRequestWrapper(HttpRequest request) : base() { _request = request; _form = new System.Collections.Specialized.NameValueCollection(request.Form); _form.Add("__RequestVerificationToken", request.Params["__RequestVerificationToken"]); } public override System.Collections.Specialized.NameValueCollection Form { get { return _form; } } public override string ApplicationPath { get { return _request.ApplicationPath; } } public override HttpCookieCollection Cookies { get { return _request.Cookies; } } }
Es gibt noch einige andere Dinge, die an unserer Lösung anders sind (insbesondere verwenden wir ein HttpModule, damit wir nicht jedem einzelnen POST das Attribut hinzufügen müssen), die ich zugunsten der Kürze ausgelassen habe. Ich kann es bei Bedarf hinzufügen.
quelle
Leider basieren die anderen Antworten auf einer von jquery verarbeiteten Anforderungsformatierung, und keine davon funktionierte beim direkten Einstellen der Nutzdaten. (Um fair zu sein, hätte es funktioniert, es in den Header zu setzen, aber ich wollte diesen Weg nicht gehen.)
Um dies in der
beforeSend
Funktion zu erreichen, funktioniert Folgendes.$.params()
transformiert das Objekt in das Standardformular / URL-codierte Format.Ich hatte alle möglichen Variationen von Stringing Json mit dem Token ausprobiert und keine davon funktionierte.
$.ajax({ ...other params..., beforeSend: function(jqXHR, settings){ var token = ''; //get token data = { '__RequestVerificationToken' : token, 'otherData': 'value' }; settings.data = $.param(data); } });
`` `
quelle
Sie sollten AntiForgeryToken in ein Formular-Tag einfügen:
@using (Html.BeginForm(actionName:"", controllerName:"",routeValues:null, method: FormMethod.Get, htmlAttributes: new { @class="form-validator" })) { @Html.AntiForgeryToken(); }
Ändern Sie dann in Javascript den folgenden Code
var DataToSend = []; DataToSend.push(JSON.stringify(data), $('form.form-validator').serialize()); $.ajax({ dataType: 'JSON', contentType: 'application/json; charset=utf-8', url: url, type: 'POST', context: document.body, data: DataToSend, success: function() { refresh(); } });
Dann sollten Sie in der Lage sein, die Anforderung mithilfe von ActionResult-Annotationen zu validieren
Ich hoffe das hilft.
quelle