2012-08-30 4 views
7

Also habe ich meinen Kopf gegen die Wand geschlagen, und ich kann keine guten Quellen dafür finden. Vielleicht vergesse ich, wie das Model-Binding-Zeug in MVC3 funktioniert, aber hier ist, was ich versuche: Ich habe einen Editor, der mit Knockout verbunden ist, um mit der Bearbeitung eines Modells zu arbeiten. Es gibt nicht viel zu dem Modell:Veröffentlichen eines JSON-Modells auf ASP.Net MVC3 mit Anti-Fälschungs-Token

public class SetupTemplate 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Template { get; set; } 
} 

Die Signatur der Aktion i zu nennen bin versucht:

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult UpdateTemplate(SetupTemplate template) 

Aus einer anderen Frage auf hier, ich diese eher hilfreich Schnipsel abgeholt bekommen die Fälschungs token:

window.addAntiForgeryToken = function(data) { 
    data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val(); 
    return data; 
}; 

die alle zusammen kommt mit mir versuchen, ein Update über ajax schreiben:

payload = window.addAntiForgeryToken(ko.mapping.toJS(self.data)); 
$.ajax({ 
    type: "post", 
    url: endpoint, 
    data: payload, 
    success: function(data) { 
     //Handle success 
    }}); 

, die in Form Datenteil der Chrome-Entwickler-Tool in diesen Ergebnisse

Id:1 
Name:Greeting 
Template: [Template Text] 
__RequestVerificationToken: [The really long anti-forgery token] 

Der Fälschungstoken wird aufgenommen, aber mein Modell ist null. Die meisten Beispiele, die ich gesehen habe, verwenden nur einen einzigen übergebenen Parameter und kein Modell.

Ich bin sicher, ich vermisse etwas Offensichtliches, irgendwelche Erkenntnisse darüber, was es sein könnte?

EDIT: Als Reaktion auf @ Mark, um das Gespräch zu diesem Wechsel:

$.ajax({ 
type: "post", 
dataType: "json", 
contentType: 'application/json', 
url: endpoint, 
data: JSON.stringify(payload), 
success: function(data) { 
    //Do some stuff 
}}); 

Ergebnisse in einer Anfrage-Payload dieses:

{"Id":1,"Name":"Greeting","Template":"...","__RequestVerificationToken":"..."}: 

Und der Server die Anti-Abholung Fälschungs-Token. Dies wurde sowohl mit als auch ohne die contentType Parameter an $.ajax() versucht.

Antwort

1

@ Mark bekommt Kredit mich für die Führung, den richtigen Weg für diese nach unten, und zeigte mir ein paar Links, die jetzt lassen Sie mich die Antifälschungs Griff Token ziemlich transparent. Doch was löste das Problem ändert:

public ActionResult UpdateTemplate(SetupTemplate template) 

zu:

public ActionResult UpdateTemplate(SetupTemplate model) 

Und jetzt ist es richtig in den Werten zu füllen. Ich würde wirklich gerne wissen, warum das behoben wurde, aber im Moment funktioniert es.

1

Können Sie versuchen, JSON.stringify zu verwenden?

$.ajax({  
    type: "post",  
    url: endpoint,  
    data: JSON.stringify(payload),  
    success: function(data) {   
     //Handle success  
    } 
}); 
+0

Ich aktualisierte meine Frage mit einer Antwort darauf. Kurz gesagt: immer noch keine Würfel. –

+1

Ist dieser Post http://haacked.com/archive/2011/10/10/preventing-csrf-with-ajax.aspx hilft Ihnen? – VJAI

+0

und das http://StackOverflow.com/Questions/2906754/How-Cani-Supply-an-antiforgerytoken-when-posting-JSON-Data-using-Ajax – VJAI

2

Das Mapping hat nicht mit dem Parameter als Vorlage funktioniert, da es mit einer der gleichnamigen Eigenschaft kollidiert (Bearing Case). Wenn Sie etwas anderes als Vorlage verwenden, funktioniert es gut für diesen Controller-Parameter.

Es gibt einen so Link, der die Details erklärt, ich bin nicht in der Lage, das jetzt leicht zu finden.

public class SetupTemplate 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Template { get; set; } 
} 
2

Hier ist meine Lösung.Definieren Sie eine jQuery-Funktion wie folgt aus:

(function ($) { 
    $.getAntiForgeryToken = function() { 
     return $('input[name="__RequestVerificationToken"]').val(); 
    }; 

    // (!) use ValidateJsonAntiForgeryToken attribute in your controller 
    $.ajaxJsonAntiforgery = function (settings) { 

     var headers = {}; 
     headers['__RequestVerificationToken'] = $.getAntiForgeryToken(); 

     settings.dataType = 'json'; 
     settings.contentType = 'application/json; charset=utf-8'; 
     settings.type = 'POST'; 
     settings.cache = false; 
     settings.headers = headers; 
     return $.ajax(settings); 
    }; 
})(jQuery); 

Es setzt nur Ihre Überprüfung Token-Header. Sie müssen auch Filter-Attribut, um Ihre Anti-Roger-Token zu überprüfen. Hier ist sie:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web; 
using System.Web.Helpers; 
using System.Web.Mvc; 

namespace MyProject.Web.Infrastructure.Filters 
{ 

    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, 
        AllowMultiple = false, Inherited = true)] 
    public sealed class ValidateJsonAntiForgeryTokenAttribute 
           : FilterAttribute, IAuthorizationFilter 
    { 
     public void OnAuthorization(AuthorizationContext filterContext) 
     { 
      if (filterContext == null) 
      { 
       throw new ArgumentNullException("filterContext"); 
      } 

      var httpContext = filterContext.HttpContext; 
      var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName]; 
      AntiForgery.Validate(cookie != null ? cookie.Value : null, 
           httpContext.Request.Headers["__RequestVerificationToken"]); 
     } 
    } 
} 

In Ihrem Controller ist es wirklich einfach, markieren Sie es einfach mit neuem Attribute (ValidateJsonAntiForgeryToken):

[Authorize, HttpPost, ValidateJsonAntiForgeryToken] 
public ActionResult Index(MyViewModel viewModel) 

Und auf der Client-Seite:

$.ajaxJsonAntiforgery({ 
    data: dataToSave, 
    success: function() { alert("success"); }, 
    error: function() { alert("error"); } 
}); 

Es funktioniert für mich. Genießen!

+1

Das hat wie ein Champ @ Roman-Pushkin funktioniert. Vielen Dank, dass Sie Ihre Lösung veröffentlicht haben. –

+0

Nach einiger Zeit habe ich festgestellt, dass "__RequestVerificationToken" kein guter Name ist. Es ist besser, "X-RequestVerificationToken" zu wählen, damit die Proxy-Server diese Header durchlaufen lassen. –

0

Eigentlich funktionierte das Folgende für mich mit einem komplexen Objekt;

var application = { 
    Criteria: { 
     ReferenceNumber: $("input[name='Criteria.ReferenceNumber'").val() 
    }, 
    AppliedVia: "Office" 
}; 

// get the next step 
$.ajax({ 
    url: form.attr("action"), 
    dataType: "html", 
    type: "POST", 
    data: { 
     __RequestVerificationToken: $("input[name=__RequestVerificationToken]").val(), 
     application: application 
    }, 
} 

Eine Sache Bemerkenswert ist jedoch, um sicherzustellen, dass die linke application in data sollte der tatsächliche Parametername in Ihrer Methode/Aktion sein. Dies funktioniert ab MVC 5 (vor .NET Core)

Verwandte Themen