如何在Fetch中使用AntiForgeryToken?

14 浏览
0 Comments

如何在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);
    });

0
0 Comments

如何在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请求中发送令牌。

0