MVC 5 多个防伪令牌 AJAX
MVC 5 Multiple Anti Forgery tokens AJAX
我的问题是我有一个局部视图,其中包含一个充满下拉菜单的表单。我正在使用 AJAX 动态更新下拉内容。在我实施防伪令牌之前一切正常。在 ajax post 中序列化我的表单后,我在 _LoginPartial.cshtml
表单中获取了防伪标记,在 posting 中获取了防伪标记来自 _config.cshtml
的数据。这导致验证属性取消 post 并停止 ajax 工作。
我试过以下方法:
删除所有标记,只在 _Layout.cshtml
页面中放置一个标记,并在 ajax 调用中引用它。这适用于 Ajax 但是在提交表单时我收到一个找不到令牌的错误,因为令牌不在表单中。
然后我也尝试 post 使用 AJAX 编辑表单并引用 _Layout.cshtml
视图中的单个标记。这将数据返回到 ajax 而不是我希望的整个视图。
我的问题是:
- 如何只将当前表单标记放入 ajax post 函数?
- 或者,是否有正确的方法来完成我想做的事情?
我很确定有一种简单的方法可以解决这个问题,但我真的只是这一切的初学者,我正在努力寻找自己的立足点。任何帮助,将不胜感激。
_LoginPartial.cshtml
@using Microsoft.AspNet.Identity
@using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
if (Request.IsAuthenticated)
{
<ul class="nav navbar-nav navbar-right">
<li>
@Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
</li>
@if (User.IsInRole("admin"))
{
<li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
}
<li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
</ul>
}
else
{
<ul class="nav navbar-nav navbar-right">
@if (User.IsInRole("admin"))
{
<li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
}
<li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
</ul>
}
_Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - Doogies Website</title>
@Styles.Render("~/Content/css")
@Styles.Render("~/Content/themes/base/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryui")
@Scripts.Render("~/bundles/jqueryval")
</head>
<body>
@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "_AFT"})) { @Html.AntiForgeryToken()}
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("Doogies Site", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
<li>@Html.ActionLink("RTCG", "RTCG_Configurator", "Rtcg")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content" >
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - Chris Duguid</p>
</footer>
</div>
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
_config.cshtml(表单所在的部分视图)
是的,我知道该表单没有提交信息。我正在尝试使用 ajax.
提交
@model HomeWeb.Models.RtcgConfigurationModel
@using (Html.BeginForm( new { enctype = "multipart/form-data" , id = "configform"}))
{
<div class="form-horizontal">
<h3>Configure RTCG</h3>
<hr />
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(model => model.RtcgCabinetType, "Cabinet Type", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgCabinetType, Model.Cabinets, new { onchange = "changed();" })
@Html.ValidationMessageFor(model => model.RtcgCabinetType)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgAdaptorType, "Adaptor Type", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgAdaptorType, Model.Adaptors, new { onchange = "changed();" })
@Html.ValidationMessageFor(model => model.RtcgAdaptorType)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgQtyAdaptors, "Adaptor Qty.", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgQtyAdaptors, Model.AdaptorQtys, new { onchange = "changed();" })
@Html.ValidationMessageFor(model => model.RtcgQtyAdaptors)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgTerminationMethod, "Termination", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgTerminationMethod, Model.TerminationMethods)
@Html.ValidationMessageFor(model => model.RtcgTerminationMethod)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgFaceplateStyle, "Faceplate Style", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgFaceplateStyle, Model.FacePlateStyles)
@Html.ValidationMessageFor(model => model.RtcgFaceplateStyle)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgScreenPrinting, "Screenprinting", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgScreenPrinting, Model.ScreenPrintOptions)
@Html.ValidationMessageFor(model => model.RtcgScreenPrinting)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgApplication, "Fibre Type", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgApplication, Model.Applications)
@Html.ValidationMessageFor(model => model.RtcgApplication)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgVerminProof, "Vermin Proof", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgVerminProof, Model.VerminProofing)
@Html.ValidationMessageFor(model => model.RtcgVerminProof)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-5 col-md-10">
<input value="Get Quotation" class="btn btn-primary" style="float: none" onclick="submitajax()" />
</div>
</div>
</div>
}
<script type="text/javascript">
function changed() {
var tokensource = $('#_AFT');
var formData = $('form').serialize();
var token = $('input[name="__RequestVerificationToken"]', tokensource).val();
$.extend(formData, { '__RequestVerificationToken': token });
$.ajax({
url: '/Rtcg/Ajax_DropdownChanged',
type: "POST",
data: formData,
success: function (result) {
$('#config-form').html(result);
},
})
}
function submitajax() {
var tokensource = $('#_AFT');
var formData = $('form').serialize();
var token = $('input[name="__RequestVerificationToken"]', tokensource).val();
$.extend(formData, { '__RequestVerificationToken': token });
$.ajax({
url: '/Rtcg/updateDB',
type: "POST",
data: formData,
success: function (result) {
},
})
}
</script>
RTCG_Configurator('index' 主体渲染时呈现的视图)
@model HomeWeb.Models.RtcgConfigurationModel
@{
ViewBag.Title = "RTCG Configurator";
}
<section >
<div class="col-md-6 pv" id="config-form">
@Html.Partial("_config")
</div>
<div class="col-md-6" >
</div>
</section>
<div style="clear:both">
<br /><br />
<p><a href="~/Home/Index" class="btn btn-primary btn-sm">« Back Home </a></p>
</div>
控制器 - Ajax_DropdownChanged()
// POST: handle dropdown changes from Ajax
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Ajax_DropdownChanged(RtcgConfigurationModel formData)
{
//handle 'postback' displaying the fields.
if (ModelState.IsValid)
{
RtcgConfigurationModel model = new RtcgConfigurationModel();
using (var db = new ApplicationDbContext())
{
model.Cabinets = DisplayElement.Cabinets(formData);
model.Adaptors = DisplayElement.Adaptors(formData);
model.AdaptorQtys = DisplayElement.AdaptorQuantities(formData);
model.TerminationMethods = DisplayElement.Termination(formData);
model.FacePlateStyles = DisplayElement.Faceplates(formData);
model.ScreenPrintOptions = DisplayElement.ScreenPrinting(formData);
model.Applications = DisplayElement.Application(formData);
model.VerminProofing = DisplayElement.VerminProof(formData);
}
return PartialView("_config", model);
//return View(model);
}
else
{
return PartialView();
}
}
问题是一个菜鸟错误。
正如斯蒂芬在他的回复中所说。我没有特别针对表格。添加 $('#configform').serialize() 就可以了。
我将令牌添加到每个表单并将其从布局页面中删除。
这是我的 ajax 代码。
<script type="text/javascript">
function changed() {
$.ajax({
url: '/Rtcg/Ajax_DropdownChanged',
type: "POST",
data: $('#configform').serialize(),
success: function (result) {
$('#config-form').html(result);
},
})
}
</script>
斯蒂芬应该披着斗篷。
您对 var formData = $('form').serialize();
的使用将序列化视图中所有表单中所有表单控件的值,包括防伪标记,这就是您提交多个标记的原因。
确保每个表单都有一个 id
属性,然后只提交带有 id="configform"
的表单中的值(和令牌),使用
var formData = $('#configform').serialize();
另请注意,您不需要
var token = $('input[name="__RequestVerificationToken"]', tokensource).val();
$.extend(formData, { '__RequestVerificationToken': token });
因为 .serialize()
已经包含令牌的 name/value 对(假设 @Html.AntiForgeryToken()
包含在 <form>
标签之间)
我的问题是我有一个局部视图,其中包含一个充满下拉菜单的表单。我正在使用 AJAX 动态更新下拉内容。在我实施防伪令牌之前一切正常。在 ajax post 中序列化我的表单后,我在 _LoginPartial.cshtml
表单中获取了防伪标记,在 posting 中获取了防伪标记来自 _config.cshtml
的数据。这导致验证属性取消 post 并停止 ajax 工作。
我试过以下方法:
删除所有标记,只在
_Layout.cshtml
页面中放置一个标记,并在 ajax 调用中引用它。这适用于 Ajax 但是在提交表单时我收到一个找不到令牌的错误,因为令牌不在表单中。然后我也尝试 post 使用 AJAX 编辑表单并引用
_Layout.cshtml
视图中的单个标记。这将数据返回到 ajax 而不是我希望的整个视图。
我的问题是:
- 如何只将当前表单标记放入 ajax post 函数?
- 或者,是否有正确的方法来完成我想做的事情?
我很确定有一种简单的方法可以解决这个问题,但我真的只是这一切的初学者,我正在努力寻找自己的立足点。任何帮助,将不胜感激。
_LoginPartial.cshtml
@using Microsoft.AspNet.Identity
@using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
{
if (Request.IsAuthenticated)
{
<ul class="nav navbar-nav navbar-right">
<li>
@Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
</li>
@if (User.IsInRole("admin"))
{
<li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
}
<li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
</ul>
}
else
{
<ul class="nav navbar-nav navbar-right">
@if (User.IsInRole("admin"))
{
<li>@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink" })</li>
}
<li>@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })</li>
</ul>
}
_Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - Doogies Website</title>
@Styles.Render("~/Content/css")
@Styles.Render("~/Content/themes/base/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryui")
@Scripts.Render("~/bundles/jqueryval")
</head>
<body>
@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "_AFT"})) { @Html.AntiForgeryToken()}
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("Doogies Site", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
<li>@Html.ActionLink("RTCG", "RTCG_Configurator", "Rtcg")</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</div>
<div class="container body-content" >
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - Chris Duguid</p>
</footer>
</div>
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
_config.cshtml(表单所在的部分视图)
是的,我知道该表单没有提交信息。我正在尝试使用 ajax.
提交@model HomeWeb.Models.RtcgConfigurationModel
@using (Html.BeginForm( new { enctype = "multipart/form-data" , id = "configform"}))
{
<div class="form-horizontal">
<h3>Configure RTCG</h3>
<hr />
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(model => model.RtcgCabinetType, "Cabinet Type", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgCabinetType, Model.Cabinets, new { onchange = "changed();" })
@Html.ValidationMessageFor(model => model.RtcgCabinetType)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgAdaptorType, "Adaptor Type", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgAdaptorType, Model.Adaptors, new { onchange = "changed();" })
@Html.ValidationMessageFor(model => model.RtcgAdaptorType)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgQtyAdaptors, "Adaptor Qty.", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgQtyAdaptors, Model.AdaptorQtys, new { onchange = "changed();" })
@Html.ValidationMessageFor(model => model.RtcgQtyAdaptors)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgTerminationMethod, "Termination", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgTerminationMethod, Model.TerminationMethods)
@Html.ValidationMessageFor(model => model.RtcgTerminationMethod)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgFaceplateStyle, "Faceplate Style", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgFaceplateStyle, Model.FacePlateStyles)
@Html.ValidationMessageFor(model => model.RtcgFaceplateStyle)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgScreenPrinting, "Screenprinting", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgScreenPrinting, Model.ScreenPrintOptions)
@Html.ValidationMessageFor(model => model.RtcgScreenPrinting)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgApplication, "Fibre Type", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgApplication, Model.Applications)
@Html.ValidationMessageFor(model => model.RtcgApplication)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.RtcgVerminProof, "Vermin Proof", new { @class = "control-label col-md-5" })
<div class="col-md-7">
@Html.DropDownListFor(model => Model.RtcgVerminProof, Model.VerminProofing)
@Html.ValidationMessageFor(model => model.RtcgVerminProof)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-5 col-md-10">
<input value="Get Quotation" class="btn btn-primary" style="float: none" onclick="submitajax()" />
</div>
</div>
</div>
}
<script type="text/javascript">
function changed() {
var tokensource = $('#_AFT');
var formData = $('form').serialize();
var token = $('input[name="__RequestVerificationToken"]', tokensource).val();
$.extend(formData, { '__RequestVerificationToken': token });
$.ajax({
url: '/Rtcg/Ajax_DropdownChanged',
type: "POST",
data: formData,
success: function (result) {
$('#config-form').html(result);
},
})
}
function submitajax() {
var tokensource = $('#_AFT');
var formData = $('form').serialize();
var token = $('input[name="__RequestVerificationToken"]', tokensource).val();
$.extend(formData, { '__RequestVerificationToken': token });
$.ajax({
url: '/Rtcg/updateDB',
type: "POST",
data: formData,
success: function (result) {
},
})
}
</script>
RTCG_Configurator('index' 主体渲染时呈现的视图)
@model HomeWeb.Models.RtcgConfigurationModel
@{
ViewBag.Title = "RTCG Configurator";
}
<section >
<div class="col-md-6 pv" id="config-form">
@Html.Partial("_config")
</div>
<div class="col-md-6" >
</div>
</section>
<div style="clear:both">
<br /><br />
<p><a href="~/Home/Index" class="btn btn-primary btn-sm">« Back Home </a></p>
</div>
控制器 - Ajax_DropdownChanged()
// POST: handle dropdown changes from Ajax
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Ajax_DropdownChanged(RtcgConfigurationModel formData)
{
//handle 'postback' displaying the fields.
if (ModelState.IsValid)
{
RtcgConfigurationModel model = new RtcgConfigurationModel();
using (var db = new ApplicationDbContext())
{
model.Cabinets = DisplayElement.Cabinets(formData);
model.Adaptors = DisplayElement.Adaptors(formData);
model.AdaptorQtys = DisplayElement.AdaptorQuantities(formData);
model.TerminationMethods = DisplayElement.Termination(formData);
model.FacePlateStyles = DisplayElement.Faceplates(formData);
model.ScreenPrintOptions = DisplayElement.ScreenPrinting(formData);
model.Applications = DisplayElement.Application(formData);
model.VerminProofing = DisplayElement.VerminProof(formData);
}
return PartialView("_config", model);
//return View(model);
}
else
{
return PartialView();
}
}
问题是一个菜鸟错误。
正如斯蒂芬在他的回复中所说。我没有特别针对表格。添加 $('#configform').serialize() 就可以了。
我将令牌添加到每个表单并将其从布局页面中删除。
这是我的 ajax 代码。
<script type="text/javascript">
function changed() {
$.ajax({
url: '/Rtcg/Ajax_DropdownChanged',
type: "POST",
data: $('#configform').serialize(),
success: function (result) {
$('#config-form').html(result);
},
})
}
</script>
斯蒂芬应该披着斗篷。
您对 var formData = $('form').serialize();
的使用将序列化视图中所有表单中所有表单控件的值,包括防伪标记,这就是您提交多个标记的原因。
确保每个表单都有一个 id
属性,然后只提交带有 id="configform"
的表单中的值(和令牌),使用
var formData = $('#configform').serialize();
另请注意,您不需要
var token = $('input[name="__RequestVerificationToken"]', tokensource).val();
$.extend(formData, { '__RequestVerificationToken': token });
因为 .serialize()
已经包含令牌的 name/value 对(假设 @Html.AntiForgeryToken()
包含在 <form>
标签之间)