C# 使用System.Net.Http.HttpClient和MVC提供反伪造令牌

C# 使用System.Net.Http.HttpClient和MVC提供反伪造令牌,c#,asp.net-mvc,winforms,asp.net-mvc-4,winforms-to-web,C#,Asp.net Mvc,Winforms,Asp.net Mvc 4,Winforms To Web,我有一个WPF(我猜可能是任何winform)应用程序,它试图使用HttpClient登录到标准MVC5网站 通常,我可以通过调用PostAsync()成功登录,在HttpContent中提供用户名和密码参数 但是,当我将[ValidateAntiForgeryToken]添加到控制器的登录(POST)操作时,PostAsync()调用失败,并出现内部服务器错误 我尝试从一个简单的GET请求中收集“\uuu RequestVerificationToken”,并通过将其添加到POST参数、请求头

我有一个WPF(我猜可能是任何winform)应用程序,它试图使用HttpClient登录到标准MVC5网站

通常,我可以通过调用PostAsync()成功登录,在HttpContent中提供用户名和密码参数

但是,当我将[ValidateAntiForgeryToken]添加到控制器的登录(POST)操作时,PostAsync()调用失败,并出现内部服务器错误

我尝试从一个简单的GET请求中收集“\uuu RequestVerificationToken”,并通过将其添加到POST参数、请求头或HttpHandler的CookieContainer(或三者的任意组合)将其与POST请求一起发送,但仍然从服务器收到错误500

我知道这可以通过HttpWebRequests()完成,但我不知道在使用HttpClient时我缺少了什么。我也不知道服务器端到底出了什么问题。。或者如何检查,因为代码从未到达我的控制器方法

有没有其他人尝试过

编辑1

我正在为GET和POST添加浏览器发送的原始数据:

GET http://localhost:57457/Account/Login HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Referer: http://localhost:57457/Account/Login
Accept-Language: en-US
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
DNT: 1
Host: localhost:57457
Cookie: NavigationTreeViewState=%5b%7b%27N0_1%27%3a%27T%27%2c%27N0%27%3a%27T%27%7d%2c%27N0_1_2%27%2c%7b%7d%5d; style=default; __RequestVerificationToken=Bak42Ga5sHJitYlmut6OgvmqXNmP7kKQRNaMSsLMAUh86iHGGmz5pnNfz_soKu46Wax9sG23arPOTnSh1bvaWyWqQ9NH4GJxFmendW8VFTg1

RESPONSE:
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Server: Microsoft-IIS/8.0
X-AspNetMvc-Version: 5.2
X-Frame-Options: SAMEORIGIN
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcRUJTLkNvZGVcUHJvamVjdHNcQ1ZSUE9TX1dlYlNpdGVcQ1ZSUE9TX1dlYlNpdGVcQWNjb3VudFxMb2dpbg==?=
X-Powered-By: ASP.NET
Date: Thu, 04 Dec 2014 10:00:00 GMT
Content-Length: 1734
[View page content]
GET http://localhost:57457/Account/Login HTTP/1.1
Host: localhost:57457
Connection: Keep-Alive

POST http://localhost:57457/Account/Login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:57457
Cookie: __RequestVerificationToken=df9nBSP_J1IiLrv84RwrkmvbYBrnH4iqv97wRvz6HMPLWBhgI4XzGeAFcschovHwD8mTtHU6xrmVxz1Ku96_BaoB79le_vLTcrgGemU4gjc1
Content-Length: 163
Expect: 100-continue

__RequestVerificationToken=df9nBSP_J1IiLrv84RwrkmvbYBrnH4iqv97wRvz6HMPLWBhgI4XzGeAFcschovHwD8mTtHU6xrmVxz1Ku96_BaoB79le_vLTcrgGemU4gjc1&UserName=test&Password=test

编辑2

这是我的应用程序为GET和POST发送的内容:

GET http://localhost:57457/Account/Login HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Referer: http://localhost:57457/Account/Login
Accept-Language: en-US
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
DNT: 1
Host: localhost:57457
Cookie: NavigationTreeViewState=%5b%7b%27N0_1%27%3a%27T%27%2c%27N0%27%3a%27T%27%7d%2c%27N0_1_2%27%2c%7b%7d%5d; style=default; __RequestVerificationToken=Bak42Ga5sHJitYlmut6OgvmqXNmP7kKQRNaMSsLMAUh86iHGGmz5pnNfz_soKu46Wax9sG23arPOTnSh1bvaWyWqQ9NH4GJxFmendW8VFTg1

RESPONSE:
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Vary: Accept-Encoding
Server: Microsoft-IIS/8.0
X-AspNetMvc-Version: 5.2
X-Frame-Options: SAMEORIGIN
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?RDpcRUJTLkNvZGVcUHJvamVjdHNcQ1ZSUE9TX1dlYlNpdGVcQ1ZSUE9TX1dlYlNpdGVcQWNjb3VudFxMb2dpbg==?=
X-Powered-By: ASP.NET
Date: Thu, 04 Dec 2014 10:00:00 GMT
Content-Length: 1734
[View page content]
GET http://localhost:57457/Account/Login HTTP/1.1
Host: localhost:57457
Connection: Keep-Alive

POST http://localhost:57457/Account/Login HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: localhost:57457
Cookie: __RequestVerificationToken=df9nBSP_J1IiLrv84RwrkmvbYBrnH4iqv97wRvz6HMPLWBhgI4XzGeAFcschovHwD8mTtHU6xrmVxz1Ku96_BaoB79le_vLTcrgGemU4gjc1
Content-Length: 163
Expect: 100-continue

__RequestVerificationToken=df9nBSP_J1IiLrv84RwrkmvbYBrnH4iqv97wRvz6HMPLWBhgI4XzGeAFcschovHwD8mTtHU6xrmVxz1Ku96_BaoB79le_vLTcrgGemU4gjc1&UserName=test&Password=test
最后是错误:

[HttpAntiforyException(0x80004005):验证提供的防伪令牌失败。已交换cookie“\uu RequestVerificationToken”和表单字段“\uu RequestVerificationToken”。]


谢谢

您可能需要在请求中包含aspnet会话id cookie

编辑: 好的,这不是会话id,但您需要两个令牌才能发送回post操作

我认为您所做的错误是对两个令牌使用相同的值,但它们应该不同,尽管两个令牌的名称都是u RequestVerificationToken。
从cookie抓取的令牌应作为cookie发送回,从表单字段抓取的令牌将作为表单字段返回。

这是因为您在应用程序的帖子中缺少来自
HtmlHelper.AntiForgeryToken()
的防伪令牌


您需要从WPF应用程序加载一个页面,该页面的视图上有
HtmlHelper.AntiForgeryToken()
。然后获取名为
\uu RequestVerificationToken
的隐藏输入元素的值,并将其附加到服务器的登录POST请求中。

谢谢,但我认为情况并非如此。这样做真的没有任何意义,而且,当我在没有[ValidateAntiForgeryToken]的情况下登录时,我不会传递任何会话id,它工作得很好。据我所知,生成的伪造令牌绑定到一个会话值,出于安全原因,该会话值留在服务器上,因此请求该令牌,然后在登录期间进行验证,应该在同一个会话中发生。就服务器而言,所有事情都在同一个会话中发生。话虽如此,我仍然怀疑会话是否与此有关(您可以从我的编辑中看到浏览器正在使用哪些数据/cookie)是的,就是这样!有两个令牌值,我愚蠢地只为这两个值发送cookie值。现在,这个错误确实很有意义:)。万分感谢!抱歉,我的问题中遗漏了这些信息,但我也尝试了:我提出了一个GET请求,找到了_RequestVerificationToken,并将其添加到我能想到的所有地方:post参数(模拟隐藏的浏览器字段)、请求头(因为我看到浏览器也这样做)和cookie(因为我的第一个GET请求将它放在了那里)。遗憾的是,它们在任何组合中都不起作用。@raptor您是否尝试过使用类似Fiddler的东西来检查真实的登录请求,然后查看您的应用程序提交了什么?非常抱歉,但我不知道如何使用Fiddler来监视应用程序。当我使用应用程序登录时,它不会显示任何流量。现在我将获得的数据添加到问题中在我的浏览器中,我将研究如何(或是否)使用fiddler监控应用程序,并给出我的发现。经过多次痛苦的尝试后,我成功地使用了fiddler(IIS交互可用的文档大多具有误导性)。我将结果添加到我的问题中。一件好事是,我看到了实际的错误。也许现在我可以理解它的意思:)您也可以发布原始http响应吗?顺便说一句,仅发布标题