用程序登录Aps.Net页面

** 问题 **

在写 Internet 应用程序的时候,常常需要处理用户登录的情况。一般来说,对于这种情况,我们是使用程序来模拟用户在 Web 页面上填写用户名、密码并提交的过程。当用户在 Web 页面上输入了用户名、密码并提交之后,实际上是触发了一个 POST 请求,在这个请求中包含有用户名、密码等信息。因此,我们只要在程序中将相关信息封装成一条 POST 请求,并将它发送给 Web Server ,基本上就能实现登录了。以 MFC 为例,下面的这段代码模拟了一个登录过程:

CString strHeaders = _T("Content-Type: application/x-www-form-urlencoded");

// name = "sam", password = "123", action = "submit"

CString strFormData = _T("name=sam&password=123&action=submit");

CInternetSession session;

CHttpConnection* pConnection =

session.GetHttpConnection(_T("ServerNameHere"));

CHttpFile* pFile =

pConnection->OpenRequest(CHttpConnection::HTTP_VERB_POST,

_T("FormActionHere"));

BOOL result = pFile->SendRequest(strHeaders,

(LPVOID)(LPCTSTR)strFormData, strFormData.GetLength());

这个方法对于 Asp 页面很有效,但对于 Asp.Net 页面,有时却不起作用,这是为什么呢?

** 研究 **

为了搞清出 Asp.Net 页面在处理登录时与 Asp 页面有何区别,我们需要使用 Sniffer 工具来跟踪 Web 服务器与浏览器之间的通讯。经过跟踪会发现, Asp.Net 页面在用户提交登录信息之后,仍然是使用 POST 请求将相关信息发送给服务器。所不同的是,处理用户名、密码等信息之外还多了一个 __VIEWSTATE 。如果在上面代码中的 strFormData 中加上一个通过 Sniffer 得到的 __VIEWSTATE 的话,就能够成功模拟出整个登录过程了。接下来的问题就是,我们应该如何获得这个 __VIEWSTATE 呢?

我们知道, Asp.Net 页面有一个 ViewState 属性, Asp.Net 用它来保存页面的状态信息,以便在页面提交失败时,能够恢复页面的状态。它是通过页面中的一个隐藏的域来定义的,如果通过浏览器来 View Source 的话,可以看到它是如下的一行代码:

1<input name="__VIEWSTATE" type="hidden" value="dDwtMTI4ODQyNDA1Ozs+lhWR3hjHp3u/496m+cT53Ofw4P4="/>

它的 value 值正是我们所需要的,我们只要从登录页面中解析出这个 __VIEWSTATE 的 value ,我们的问题就能够得到解决了。

** 解决 **

仔细看一下, ViewState 的值是经过编码的,先不管它,直接将它从页面中取出,和登录信息一起组成 POST 请求,发送给 Server ,结果如何呢?失败了 L 。对比一下 Sniffer 的结果和页面中 ViewState 的 value ,我们会发现,它们之间还是有些许不同的。原来,页面源码中的 ViewState 值是经过 Base64 编码的,而当它被发送给 Web Server 时,为了保证传输的正确,浏览器会将它转换成 URL 编码,当 Web Server 接收到 ViewState 之后,当然会先将它从 URL 编码解码为 Base64 编码再交给 Asp.Net 处理。看来我们需要将 ViewState 的值在进行一边 URL 编码处理,这样就能够成功模拟整个登录过程了 J 。

** 参考 **

1. HOWTO: Simulate a Form POST Request Using WinInet ,微软的 KB 文章,描述了模拟 POST 请求的实现。

2. ASP .NET Maintaining the ViewState , ViewState 的入门知识。

3. ViewState: All You Wanted to Know ,关于 ViewState 的深入讨论。

4. ViewState Parser ,想看看解码后的 ViewState 是什么样子吗?试试这个 Parser 。

5. 博客堂中的相关讨论 ,这是我在解决这个问题的过程中,在 博客堂 写的 Blog 。

Published At
Categories with Web编程
Tagged with
comments powered by Disqus