Публикация модели JSON в ASP.Net MVC3 с токеном защиты от подделки

Итак, я бился головой об стену с этим, и я не могу найти хороших источников для этого. Может быть, я забыл, как работает механизм привязки модели в MVC3, но вот что я пытаюсь сделать: у меня есть какой-то редактор, связанный с Knockout для обработки редактирования модели. Там не так много для модели:

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

Подпись действия, которое я пытаюсь вызвать:

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

Из другого вопроса, приведенного здесь, я взял этот довольно полезный фрагмент кода, чтобы получить маркер защиты от подделки:

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

Все это вместе со мной пытается опубликовать обновление через ajax:

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

Что приводит к этому в разделе данных формы инструментов разработчика Chrome

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

Токен против подделки поднят, но моя модель пуста. Большинство примеров, которые я видел, просто используют один передаваемый параметр, а не модель.

Я уверен, что упускаю что-то очевидное, какие-то идеи о том, что это может быть?

EDIT: В ответ на @Mark, изменив вызов на этот:

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

В результате получается полезная нагрузка запроса:

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

И сервер не получает токен против подделки. Это было опробовано как с, так и без параметров contentType для $.ajax().

7 голосов | спросил Matt Sieker 30 AM00000090000003831 2012, 09:19:38

5 ответов


0

@Mark получает признание за то, что он привел меня к правильному пути и указал на некоторые ссылки, которые теперь позволяют довольно прозрачно обрабатывать маркер защиты от подделки. Однако то, что решило проблему, изменилось:

public ActionResult UpdateTemplate(SetupTemplate template)

в

public ActionResult UpdateTemplate(SetupTemplate model)

И теперь он правильно заполняет значения. Я бы очень хотел знать, почему это исправило это, но пока это работает.

ответил Matt Sieker 30 PM00000060000001031 2012, 18:40:10
0

Сопоставление не работает с параметром в качестве шаблона, поскольку оно конфликтует с одним из свойств с таким же именем (регистр подшипника). Если вы используете что-то кроме шаблона, это будет хорошо работать для этого параметра контроллера.

Там есть ссылка, объясняющая детали, я не могу найти это сейчас легко.

public class SetupTemplate
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Template { get; set; }
} 
ответил gathreya 8 SatEurope/Moscow2012-12-08T01:16:50+04:00Europe/Moscow12bEurope/MoscowSat, 08 Dec 2012 01:16:50 +0400 2012, 01:16:50
0

Вот мое решение. Определите функцию jQuery следующим образом:

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

Он просто помещает ваш верификационный токен в заголовки. Вам также нужен атрибут фильтра, чтобы проверить ваш токен анти-подделки. Вот оно:

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

В вашем контроллере это действительно просто, просто пометьте его новым атрибутом (ValidateJsonAntiForgeryToken):

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

И на стороне клиента:

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

Это работает для меня. Наслаждайтесь!

ответил Roman Pushkin 19 22013vEurope/Moscow11bEurope/MoscowTue, 19 Nov 2013 15:32:35 +0400 2013, 15:32:35
0

Можете ли вы попробовать использовать JSON.stringify?

$.ajax({     
   type: "post",     
   url: endpoint,     
   data: JSON.stringify(payload),     
   success: function(data) {         
      //Handle success     
   } 
});
ответил VJAI 30 PM00000030000000531 2012, 15:32:05
0

На самом деле следующее работало для меня со сложным объектом;

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

Однако следует отметить, что левый application в data должно быть фактическим именем параметра в вашем методе /действии. Это работает с MVC 5 (до .NET Core)

ответил DiskJunky 17 PM00000030000001931 2016, 15:57:19

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132