簡體   English   中英

使用防偽令牌將JSON模型發布到ASP.Net MVC3

[英]Posting a JSON model to ASP.Net MVC3 with Anti-forgery token

因此,我一直在用這種方法把頭撞在牆上,而我找不到任何好的來源。 也許我忘記了模型綁定東西在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]

提取了防偽令牌,但是我的模型為null。 我看到的大多數示例都只使用傳遞的單個參數,而不是模型。

我確定我缺少明顯的東西,對它可能有什么見解?

編輯:響應@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":"..."}:

並且服務器未提取防偽令牌。 嘗試使用$.ajax()contentType參數是否有此方法。

映射不適用於作為模板的參數,因為它與具有相同名稱(軸承大小寫)的屬性之一發生沖突。 如果您使用模板以外的其他任何東西,則對於該控制器參數將非常有效。

有一個如此詳細的鏈接解釋細節,我現在不容易找到它。

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

這是我的解決方案。 定義一個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"); }
});

這個對我有用。 請享用!

您可以嘗試使用JSON.stringify嗎?

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

@Mark因引導我走上正確的道路而獲得稱贊,並指出了一些鏈接,這些鏈接現在使我可以相當透明地處理防偽令牌。 但是,解決問題的方法正在改變:

public ActionResult UpdateTemplate(SetupTemplate template)

至:

public ActionResult UpdateTemplate(SetupTemplate model)

現在,它可以正確地填充值。 我真的很想知道為什么可以解決這個問題,但是現在,它可以工作了。

實際上,以下內容對我來說很復雜。

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

但是,需要注意的一件事是要確保data剩余的application應該是您的方法/操作中的實際參數名稱。 從MVC 5(.NET Core之前的版本)開始運行

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM