从一个空的 MVC 项目开始,这是我的
Startup.cs
:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace AntiForgeryExample
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
}
}
这是我的
HomeController.cs
:
using Microsoft.AspNetCore.Mvc;
using System.Net;
namespace AntiForgeryExample
{
public class XyzController : Controller
{
[HttpPost]
[ValidateAntiForgeryToken]
public string Fgh() => "fgh 1";
[HttpGet]
public ContentResult Efg()
{
return new ContentResult()
{
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
Content = @"<!DOCTYPE html>
<html>
<body>
<form method=""post"" action=""/Xyz/Fgh"">
<button type=""submit"">123</Button>
</form>
</body>
</html>"
};
}
}
}
Startup.cs
中的以下行添加了防伪中间件:
services.AddMvc();
因此,如果我们转到
http://localhost:52838/Xyz/Efg
,我们将获得带有单个按钮的简单页面:
如果我们按下按钮,我们会收到 400“错误请求”响应:
我假设这是因为我们没有在帖子中传递有效的请求验证令牌。
Fgh
方法应用了 ValidateAntiForgeryToken
属性:
[HttpPost]
[ValidateAntiForgeryToken]
public string Fgh() => "fgh 1";
因此调用此方法时需要令牌。
如本页所述,如果您将
form
标签助手与 ASP.NET Core MVC 或 Razor 页面一起使用,通常会自动包含此令牌的代码。它看起来像这样,并作为 form
标签的一部分包含在内:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
在上面展示的示例程序中,我们以编程方式使用表单生成 HTML。
我的问题是,有没有一种方法可以通过 C# 以编程方式生成所需的令牌,而无需使用 MVC 视图或 Razor 页面。我们的想法是,我们获取令牌值,然后包含
input
标签:
<input name="__RequestVerificationToken" type="hidden" value="TOKEN VALUE HERE">
我在
/r/dotnet
subreddit 上分享了这个问题。
/u/kenos1
在那里提供了非常有帮助的答案:
您可以注入 Microsoft.AspNetCore.Antiforgery.IAntiforgery 并对其调用 GetTokens() 。
这是文档:链接
正如他在那里提到的,我们在
IAntiforgery
构造函数中注入 XyzController
:
private IAntiforgery antiforgery;
public XyzController(IAntiforgery antiforgery_)
{
antiforgery = antiforgery_;
}
我们在注入的
GetAndStoreTokens
实例上调用 IAntiforgery
:
var token_set = antiforgery.GetAndStoreTokens(HttpContext);
最后,我们在生成的 HTML 中使用生成的令牌:
return new ContentResult()
{
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
Content = string.Format(@"<!DOCTYPE html>
<html>
<body>
<form method=""post"" action=""/Xyz/Fgh"">
<button type=""submit"">123</Button>
<input name=""__RequestVerificationToken"" type=""hidden"" value=""{0}"">
</form>
</body>
</html>",
token_set.RequestToken)
};
这是完整的控制器文件:
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System.Net;
namespace AntiForgeryExample
{
public class XyzController : Controller
{
private IAntiforgery antiforgery;
public XyzController(IAntiforgery antiforgery_)
{
antiforgery = antiforgery_;
}
[HttpPost]
[ValidateAntiForgeryToken]
public string Fgh() => "fgh 1";
[HttpGet]
public ContentResult Efg()
{
var token_set = antiforgery.GetAndStoreTokens(HttpContext);
return new ContentResult()
{
ContentType = "text/html",
StatusCode = (int)HttpStatusCode.OK,
Content = string.Format(@"<!DOCTYPE html>
<html>
<body>
<form method=""post"" action=""/Xyz/Fgh"">
<button type=""submit"">123</Button>
<input name=""__RequestVerificationToken"" type=""hidden"" value=""{0}"">
</form>
</body>
</html>",
token_set.RequestToken)
};
}
}
}
ASP.NET Core 3.1 官方文档提到了
GetAndStoreTokens
方法这里。
在最新版本的 ASP.NET Core 中,可以手动生成令牌,如下所示:
<form method="post">
@Html.AntiForgeryToken()
</form>