提供AntiForgery令牌与System.Net.Http.HttpClient和MVC

问题描述:

我有一个WPF(可能是任何winform我猜)尝试登录到标准的MVC 5网站使用HttpClient提供AntiForgery令牌与System.Net.Http.HttpClient和MVC

Normally I can login successfully with a call to PostAsync() where I provide the UserName and Password params in a HttpContent!

然而,当我加入[ValidateAntiForgeryToken]到我的控制器的登录(POST)动作,PostAsync()调用失败,内部服务器错误。

我试图从一个简单的GET请求收集“__RequestVerificationToken”,并通过将其添加到POST参数,可以请求的报头或所述的HttpHandler的的CookieContainer(或三者的任意组合与我的POST请求发送它)但仍然从服务器收到错误500。

我知道这可以用HttpWebRequests(apparently)完成,但我不知道我在使用HttpClient时丢失了什么。我也不知道服务器端发生了什么错误,或者如何检查,因为代码永远不会达到我的控制器方法。

其他人试过这个吗?

EDIT 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] 

POST 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 
Content-Type: application/x-www-form-urlencoded 
Accept-Encoding: gzip, deflate 
Connection: Keep-Alive 
Content-Length: 180 
DNT: 1 
Host: localhost:57457 
Pragma: no-cache 
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 

__RequestVerificationToken=Bak42Ga5sHJitYlmut6OgvmqXNmP7kKQRNaMSsLMAUh86iHGGmz5pnNfz_soKu46Wax9sG23arPOTnSh1bvaWyWqQ9NH4GJxFmendW8VFTg1&UserName=test&Password=test 

RESPONSE: 
HTTP/1.1 400 Bad request (user/password for testing purposes only) 
Cache-Control: private 
Content-Type: text/html; charset=utf-8 
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: 4434 
[View page content] 

编辑2

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

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 

最后是这样的错误:

[HttpAntiForgeryException(0X80004005):提供的防伪标记验证失败。该Cookie " __RequestVerificationToken "和表单字段" __RequestVerificationToken "被交换。]

谢谢!

+0

你也可以发布原始http响应 – 2014-12-04 09:47:26

+0

只是标题btw – 2014-12-04 09:49:27

你D可能需要包括ASPNET会话cookie您的要求

编辑: 确定你是对的,它不是会话ID,但你需要两个令牌传送回您的文章的行动。

我认为你做错了什么是两个令牌使用相同的值,但它们应该是不同的,这两个令牌的名称都是__RequestVerificationToken。 从cookie中抓取的令牌应该作为cookie返回,从表单字段中抓取的令牌将作为表单字段返回。

+0

谢谢,但我不认为这种情况。这真的没有任何意义,除此之外,当我没有[ValidateAntiForgeryToken]登录时,我没有传递任何会话ID,它工作得很好。 – raptor 2014-12-03 18:40:06

+0

据我所知,生成的伪造令牌绑定到会话值,出于安全原因停留在服务器上,所以请求令牌,然后在登录过程中进行验证,应该发生在同一会话中。 – 2014-12-03 21:51:32

+0

就服务器而言,一切都发生在同一个会话中。话虽如此,我肯定怀疑会议与此有关(你可以从我的编辑看到浏览器正在使用什么数据/ cookies)的事实 – raptor 2014-12-03 22:38:28

这是因为您在应用程序中的POST中缺少来自HtmlHelper.AntiForgeryToken()的反伪造令牌。

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

+0

对不起,我从我的问题中忽略了这些信息,但我也尝试过:我发出了一个GET请求,将__RequestVerificationToken挖出并将其添加到所有我能想到的地方:后缀参数(模拟隐藏的浏览器字段),请求头(因为我看到浏览器也是这样做的)和cookie(因为我的第一个GET请求放在那里)。可悲的是,他们没有任何组合没有工作。 – raptor 2014-12-03 21:32:58

+0

@raptor你有没有尝试过使用Fiddler来检查一个真正的登录请求,然后看看你的应用程序提交? – 2014-12-03 21:37:38

+0

我很抱歉,但我不知道如何使用小提琴来监控应用程序。当我使用应用程序登录时,它不显示任何流量。现在,我向问题中添加了从浏览器获得的数据,我将研究如何(或者如果)我可以使用提琴手实际监控应用程序,并返回我的发现。 – raptor 2014-12-03 22:27:20