3

I have two .Net Core applications, a Web API and Client. Sending Post from the client using :

<form asp-action="Create" method="post">
     @Html.AntiForgeryToken()
     .....
</form>

Client controller:

public async Task<IActionResult> Create([Bind("QuestionId,TheQuestion")] SecurityQuestion securityQuestion)
{
    _session.SetString(SessionsKeys.Directory, "/SecurityQuestions");
    if (ModelState.IsValid)
    {
        var data = await _theService.PostWebApi(securityQuestion);
        if (data.Item3 == "True")
        {
            return RedirectToAction(nameof(Index));
        }
        return View(data.Item1);
    }
    return View(securityQuestion);
}

Method to communicate with the Web API:

public async Task<(object, string, string)> PostWebApi(TObject model)
{
    var dir = _session.GetString(SessionsKeys.Directory);
    using (HttpClient client = new HttpClient())
    {
        client.BaseAddress = new Uri(_webApiData.WebApiitems.Url);
        MediaTypeWithQualityHeaderValue contentType = new MediaTypeWithQualityHeaderValue("application/json");
        client.DefaultRequestHeaders.Accept.Add(contentType);
        string stringData = JsonConvert.SerializeObject(model);
        var contentData = new StringContent(stringData, System.Text.Encoding.UTF8, "application/json");
        HttpResponseMessage response = client.PostAsync(dir + "/", contentData).Result;
        var msg = await response.Content.ReadAsStringAsync();
        var theresponse = response.IsSuccessStatusCode.ToString();
        return (model,msg,theresponse);
    }
}

Web API Controller:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> PostSecurityQuestion([FromRoute] SecurityQuestion securityQuestion)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }
    _context.SecurityQuestion.Add(securityQuestion);
    await _context.SaveChangesAsync();
    return CreatedAtAction("GetSecurityQuestion", new { id = securityQuestion.QuestionId }, securityQuestion);
}

If I remove [ValidateAntiForgeryToken], it works. I also tried to remove [Form], still I get 400 error.

Am I missing any additional settings in the Startup configurations?

Frank Fajardo
  • 7,034
  • 1
  • 29
  • 47
hncl
  • 2,295
  • 7
  • 63
  • 129

2 Answers2

1

Anti-forgery tokens are used to ensure the form your client submits is the form you issued it---that is, it is not forged.

In your case, your client app is generating its own anti-forgery token via the @Html.AntiForgeryToken(). But then, it does not get passed to the HttpClient you create to talk to your Web API. But even if you manage to pass that anti-forgery token to your Web API, it will likely be rejected since it was not issued by the Web API.

You should change your Web API to allow your client to get a token. Here is a blog by Scott Allen on how you can do that:

Frank Fajardo
  • 7,034
  • 1
  • 29
  • 47
  • It makes sense, I checked the blog, could not really follow the part about Axios. Will try to find a step-by-step example. Thank you for pointing me to the right direction. – hncl Oct 01 '17 at 07:18
0

In Startup.cs file inside ConfigureServices() method add below service

services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
Mostafiz
  • 7,243
  • 3
  • 28
  • 42