如何在Fetch中使用AntiForgeryToken?
如何在Fetch中使用AntiForgeryToken?
我不确定如何在我的Fetch调用中使用AntiForgeryToken。关于AJAX的例子我在这里找到了:include antiforgerytoken in ajax post ASP.NET MVC。我能够用同样的方式来实现Fetch吗?我找不到任何相关的例子。非常感谢任何帮助。
我的控制器方法如下:
[Route("comments/new")] public ActionResult AddComment(Survey survey) { survey.Time = DateTime.Now; _context.Surveys.Add(survey); _context.SaveChanges(); return Content("Added"); }
前端代码如下:
const queryParams = `Name=${this.state.surveyState.name}&Change=${this.state.surveyState.change}&Opinion=${this.state.surveyState.opinion}`; fetch(`/comments/new?${queryParams}`) .then(res => res.json()) .then(res => { console.log(res); }) .catch(error => { console.error(error); });
如何在Fetch中使用AntiForgeryToken?
问题的出现原因是为了在使用Fetch进行POST请求时,能够使用AntiForgeryToken进行安全验证。
解决方法是在Startup.cs文件中进行配置。首先,在ConfigureServices方法中添加以下代码:
public void ConfigureServices(IServiceCollection services) { //其他代码 services.AddAntiforgery(x => x.HeaderName = "X-CSRF-TOKEN"); services.AddMvc(); }
然后,在Configure方法中添加以下代码:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IAntiforgery antiforgery) { //其他代码 app.Use(next => context => { if (context.Request.Path == "/") { //将请求令牌作为JavaScript可读的cookie发送 var tokens = antiforgery.GetAndStoreTokens(context); context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken, new CookieOptions { HttpOnly = false }); } return next(context); }); app.UseAuthentication(); app.UseStaticFiles(); //新的配置应该在此行之前 }
接下来,在SurveyController.cs文件中的POST方法中添加以下代码:
[HttpPost] [ValidateAntiForgeryToken] public IActionResult AddComment(Survey survey) { if (survey == null) { return BadRequest(); } survey.Time = DateTime.Now; _context.Surveys.Add(survey); _context.SaveChanges(); return Ok(); }
然后,在Dialog.js文件中创建一个获取cookie的函数:
function getCookie(name) { if (!document.cookie) { return null; } const csrfCookies = document.cookie.split(';') .map(c => c.trim()) .filter(c => c.startsWith(name + '=')); if (csrfCookies.length === 0) { return null; } return decodeURIComponent(csrfCookies[0].split('=')[1]); }
最后,在触发Fetch时,添加以下代码:
var csrfToken = getCookie("CSRF-TOKEN"); var url = new URL("http://localhost:58256/Survey/AddComment"), params = { Name: this.state.surveyState.name, Change: this.state.surveyState.change, Opinion: this.state.surveyState.opinion }; Object.keys(params).forEach(key => url.searchParams.append(key, params[key])); fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', "X-CSRF-TOKEN": csrfToken //发送请求时携带令牌 }, contentType: "application/json; charset=utf-8", credentials: 'include' } ) .then(res => res.json()) .then(res => { console.log(res); }) .catch(error => { console.error(error); });
需要注意的是,从安全角度考虑,cookies应该是安全的,这样就无法通过JavaScript读取cookies,否则会存在安全漏洞。因此,可以在Startup文件中进行以下配置:
services.Configure(options => { options.MinimumSameSitePolicy = SameSiteMode.Strict; options.HttpOnly = HttpOnlyPolicy.Always; options.Secure = CookieSecurePolicy.Always; });
这样就可以使用AntiForgeryToken进行安全验证,并在Fetch请求中发送令牌。