如何在集成测试中绕过表单发布的防伪令牌验证

pev*_*l27 2 c# integration-testing antiforgerytoken asp.net-core-mvc

我有一个 ASP.NET 核心 2.2 MVC 应用程序,它公开了一个带有基本表单(用户名/密码)的登录页面。控制器动作由 保护AntiForgeryTokenAttribute,隐藏__RequestVerificationToken由 MVC 添加。

我正在使用 TestServer 编写集成测试,我想发送表单并查看是否收到 302 状态代码,但找不到任何有效选项。

我评估的一个选项是执行 GET,提取 __RequestVerificationToken,然后将 tpoken 作为表单的一部分提交。但是,这将不起作用,因为我缺少 cookie(我相信)。TestServer.CreateClient不支持任何处理程序,因此我无法添加 cookie。

有没有办法测试这个?

谢谢!

pev*_*l27 6

所以需要做两件事:

  1. 在页面 GET 期间:从 Headers 中获取 cookie 并提取 __RequestVerification
  2. 提交表单时:在Headers中添加cookie并将__RequestVerification添加到模型中

1.获取

您可以使用以下方法提取令牌:

headers.FirstOrDefault(x => x.Key == "Set-Cookie").Value.First().Split(" ")[0];

// The cookie we are looking for is .AspNetCore.Antiforgery.<unique guid>=<unique guid>
var tokenCookie = cookieContent.Split("=");
var name = tokenCookie[0];
var value = tokenCookie[1];
Run Code Online (Sandbox Code Playgroud)

您可以使用 Nuget 包HtmlAgilityPack提取 __RequestVerification ,然后执行以下操作:

var htmlDoc = new HtmlDocument();
htmlDoc.LoadHtml(htmlContent);
var tokenValue = htmlDoc.DocumentNode.SelectSingleNode("//input[@name='__RequestVerificationToken']")
                .Attributes.Where(x => x.Name == "value").Select(x => x.Value).First();
Run Code Online (Sandbox Code Playgroud)

这里htmlContentHttpResponse.Content.ReadAsStringAsync();

2. 发布

When you create the form, add the __RequestVerificationToken:

new FormUrlEncodedContent(new List<KeyValuePair<string, string>>
{
    ... your stuff here
    new KeyValuePair<string, string>("__RequestVerificationToken", token)
        });
}
Run Code Online (Sandbox Code Playgroud)

then when sending the request:

var request = new HttpRequestMessage(HttpMethod.Post, endPoint)
{ Content = form };

request.Headers.Add("Cookie", $"{cookie.Name}={cookie.Value}");

await client.SendAsync(request);
Run Code Online (Sandbox Code Playgroud)

where client is HttpClient created using TestServer.CreateClient.

Hope this helps somebody else!