2012-08-30 13 views
7

Tak, waliłem głową w ścianę i nie mogę znaleźć dla niego dobrych źródeł. Być może zapominam o tym, jak modelowe elementy wiążące działają w MVC3, ale oto co próbuję zrobić: mam jakiegoś edytora związanego z Knockoutem do obsługi edycji modelu. Nie ma wiele do modelu:Umieszczanie modelu JSON na ASP.Net MVC3 z torem zabezpieczającym przed fałszerstwem

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

Podpis działania Próbuję zadzwonić to:

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

Z innego pytanie o tutaj, wziąłem to raczej jako fragment, aby uzyskać anty-fałszowanie tokena:

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

Który wszystko przychodzi razem ze mną próbuje odpowiedzieć aktualizacji za pośrednictwem ajax:

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

co skutkuje tym w sekcji formularz danych narzędzi deweloperskich Chrome

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

zabezpieczającym tokena jest odbierany, ale mój model jest null. Większość przykładów widziałem po prostu użyć jednego parametru przekazanego wzdłuż, a nie model.

Jestem pewien, że brakuje mi czegoś oczywistego, jakiegokolwiek wglądu w to, co to może być?

EDIT: W odpowiedzi na @Mark, zmieniając wezwanie do tego:

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

Skutkuje to żądanie ładowności to:

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

i serwer nie podnosząc anty- token fałszerstwa. Zostało to wypróbowane zarówno z parametrami contentType jak i bez nich, do .

Odpowiedz

1

@Mark dostaje kredyt prowadząc mnie na właściwą drogę do tego, i wskazując na mnie kilka linków, które teraz pozwól mi uchwyt anty fałszerstwa żeton dość przejrzysty. Jednak to, co rozwiązuje problem zmieniał:

public ActionResult UpdateTemplate(SetupTemplate template) 

do:

public ActionResult UpdateTemplate(SetupTemplate model) 

a teraz jest prawidłowo wypełnianie wartościami. Naprawdę chciałbym wiedzieć, dlaczego to naprawiło, ale na razie działa.

1

Czy możesz spróbować użyć JSON.stringify?

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

Zaktualizowałem moje pytanie z odpowiedzią na to. W skrócie: nadal nie ma kości. –

+1

Czy ten post http://haacked.com/archive/2011/10/10/preventing-csrf-with-ajax.aspx pomaga? – VJAI

+0

i ten http://stackoverflow.com/questions/2906754/how-can-i-supply-an-antiforgerytoken-when-posting-json-data-using-ajax – VJAI

2

Mapowanie nie działało z parametrem jako szablon, ponieważ koliduje z jedną z właściwości o tej samej nazwie (przypadek). Jeśli użyjesz czegoś innego niż szablon, będzie on działał dobrze dla tego parametru kontrolera.

Istnieje taki link wyjaśniający szczegóły, nie jestem w stanie znaleźć tego teraz łatwo.

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

Oto moje rozwiązanie.Zdefiniuj funkcję jQuery w ten sposób:

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

Po prostu umieszczasz swój token weryfikacyjny w nagłówkach. Musisz również użyć atrybutu filtra, aby sprawdzić token przeciwnika. Oto ona:

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

W kontrolerze to naprawdę proste, wystarczy zaznaczyć go z nowego atrybutu (ValidateJsonAntiForgeryToken):

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

A po stronie klienta:

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

to działa dla mnie. Cieszyć się!

+1

To działało jak mistrz @ roman-pushkin. Dziękujemy za przesłanie rozwiązania. –

+0

Po pewnym czasie stwierdziłem, że "__RequestVerificationToken" nie jest dobrą nazwą. Lepiej wybrać "X-RequestVerificationToken", więc serwery proxy pozwolą temu nagłówkowi przejść. –

0

Właściwie to, co dla mnie, działało na złożonym obiekcie;

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 
    }, 
} 

Jedno odnotowania jest jednak to, aby upewnić się, że lewa application w data powinna być rzeczywista nazwa parametru w swojej metody/działania. Działa jak MVC 5 (pre NET Core)