在 ASP.NET Core 中将 ValidateAntiForgeryToken 属性与 Unobtrusive Ajax 插件一起使用
Using ValidateAntiForgeryToken attribute with Unobtrusive Ajax plugin in ASP.NET Core
我有以下表格:
<form asp-action="GetUsersAPICall" asp-controller="UsersObject" asp-antiforgery="true" data-ajax="true" data-ajax-method="get" data-ajax-mode="replace" data-ajax-update="#userSearchResult">
Enter email or name to search for: <input type="text" id="query" name="query"/>
<input type="submit" value="Search" />
</form>
<div id="userSearchResult"></div>
(是的,我意识到我有点混合了 Unobtrusive AJAX 语法和 ASP.NET Core tag helpers)。
我的控制器中有以下操作方法:
[HttpPost]
[Authorize(Roles = "PatchUser")]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> PatchUserAPICall(UserPatchViewModel vm)
{
if (vm == null)
{
return BadRequest();
}
else if (!ModelState.IsValid)
{
return View(vm);
}
else
{
bool result = await vm.User.Update();
if (result)
{
return RedirectToAction("Confirmation");
}
else
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
}
}
这很好用,除非我取消注释 ValidateAntiForgeryToken
属性。
我见过为 jQuery AJAX 调用进行验证的示例,但其中许多依赖于在 header 中发送它(例如在 this Q&A 中).据推测,这将使 ValidateAntiForgeryToken
按预期工作(在代码中进行一些配置更改)。希望我没有遗漏一些明显的东西,但我搜索了很多,找不到如何在 Unobtrusive AJAX 中实际添加 header,所以我什至无法尝试类似的东西,看看它是否有效。
我知道您可以使用 User.IsInRole("RoleName")
作为 Authorize
属性的替代方法。有没有办法将 Anti-Forgery 令牌作为参数发送并以这种方式发送?或者有没有办法编辑 headers 并这样做?或者有没有我还没有想到的更好的方法?
一般来说,有什么方法可以在发送前编辑 Ajax 调用吗?
首先,您的 data-ajax-method="get"
应该是 data-ajax-method="post"
。这是因为您使用 asp-antiforgery="true" 会在您的表单中添加一个隐藏的 __RequestVerificationToken。通常,此隐藏字段与表单数据的其余部分一起提交。但是,__RequestVerificationToken不能在查询字符串中提交(即GET),必须在header或body(即POST)中提交.如果你做这个改变,整个事情很可能 "just work."
但是,也可以将防伪令牌放入 ajax 请求的 header 中。 jquery unobtrustive ajax 不会开箱即用,但添加起来并不难。在 jquery.unobtrusive-ajax.js 中有一个函数, asyncRequest(element, options){..}
在末尾该函数是实际的 jquery ajax 调用:
$.ajax(options);
在此调用之前,在链接代码的第 143 行,插入以下内容:
if (method === "POST") {
var token = $("input[name='__RequestVerificationToken'][type='hidden']").val();
if (token) {
options.headers = { RequestVerificationToken: token };
}
}
如果您使用 <a>
标签进行删除或其他操作,这也很有用:ajax POST:
@Html.AntiforgeryToken() //add the hidden antiforgery token, assuming you don't have a form tag.
<a href="#" data-ajax="true" data-ajax-method="post"
data-ajax-url="@Url.Action("Delete", new {Model.Id})" data-ajax-confirm="Are you sure?"
data-ajax-success="alert('success')">Delete This</a>
我有以下表格:
<form asp-action="GetUsersAPICall" asp-controller="UsersObject" asp-antiforgery="true" data-ajax="true" data-ajax-method="get" data-ajax-mode="replace" data-ajax-update="#userSearchResult">
Enter email or name to search for: <input type="text" id="query" name="query"/>
<input type="submit" value="Search" />
</form>
<div id="userSearchResult"></div>
(是的,我意识到我有点混合了 Unobtrusive AJAX 语法和 ASP.NET Core tag helpers)。
我的控制器中有以下操作方法:
[HttpPost]
[Authorize(Roles = "PatchUser")]
//[ValidateAntiForgeryToken]
public async Task<IActionResult> PatchUserAPICall(UserPatchViewModel vm)
{
if (vm == null)
{
return BadRequest();
}
else if (!ModelState.IsValid)
{
return View(vm);
}
else
{
bool result = await vm.User.Update();
if (result)
{
return RedirectToAction("Confirmation");
}
else
{
return StatusCode((int)HttpStatusCode.InternalServerError);
}
}
}
这很好用,除非我取消注释 ValidateAntiForgeryToken
属性。
我见过为 jQuery AJAX 调用进行验证的示例,但其中许多依赖于在 header 中发送它(例如在 this Q&A 中).据推测,这将使 ValidateAntiForgeryToken
按预期工作(在代码中进行一些配置更改)。希望我没有遗漏一些明显的东西,但我搜索了很多,找不到如何在 Unobtrusive AJAX 中实际添加 header,所以我什至无法尝试类似的东西,看看它是否有效。
我知道您可以使用 User.IsInRole("RoleName")
作为 Authorize
属性的替代方法。有没有办法将 Anti-Forgery 令牌作为参数发送并以这种方式发送?或者有没有办法编辑 headers 并这样做?或者有没有我还没有想到的更好的方法?
一般来说,有什么方法可以在发送前编辑 Ajax 调用吗?
首先,您的 data-ajax-method="get"
应该是 data-ajax-method="post"
。这是因为您使用 asp-antiforgery="true" 会在您的表单中添加一个隐藏的 __RequestVerificationToken。通常,此隐藏字段与表单数据的其余部分一起提交。但是,__RequestVerificationToken不能在查询字符串中提交(即GET),必须在header或body(即POST)中提交.如果你做这个改变,整个事情很可能 "just work."
但是,也可以将防伪令牌放入 ajax 请求的 header 中。 jquery unobtrustive ajax 不会开箱即用,但添加起来并不难。在 jquery.unobtrusive-ajax.js 中有一个函数, asyncRequest(element, options){..}
在末尾该函数是实际的 jquery ajax 调用:
$.ajax(options);
在此调用之前,在链接代码的第 143 行,插入以下内容:
if (method === "POST") {
var token = $("input[name='__RequestVerificationToken'][type='hidden']").val();
if (token) {
options.headers = { RequestVerificationToken: token };
}
}
如果您使用 <a>
标签进行删除或其他操作,这也很有用:ajax POST:
@Html.AntiforgeryToken() //add the hidden antiforgery token, assuming you don't have a form tag.
<a href="#" data-ajax="true" data-ajax-method="post"
data-ajax-url="@Url.Action("Delete", new {Model.Id})" data-ajax-confirm="Are you sure?"
data-ajax-success="alert('success')">Delete This</a>