我很难尝试使用webclient对accounts.google.com进行身份验证
我正在使用C#WebClient对象来实现以下功能.
我将表单字段提交到https://accounts.google.com/ServiceLoginAuth?service=oz
这是POST字段:
service=oz dsh=-8355435623354577691 GALX=33xq1Ma_CKI timeStmp= secTok= Email=test@test.xom Passwd=password signIn=Sign in PersistentCookie=yes rmShown=1
Content-Type text/html; charset=UTF-8 Strict-Transport-Security max-age=2592000; includeSubDomains Set-Cookie GAPS=1:QClFh_dKle5DhcdGwmU3m6FiPqPoqw:SqdLB2u4P2oGjt_x;Path=/;Expires=Sat,21-Dec-2013 07:31:40 GMT;Secure;HttpOnly Cache-Control no-cache,no-store Pragma no-cache Expires Mon,01-Jan-1990 00:00:00 GMT X-Frame-Options Deny X-Auto-Login realm=com.google&args=service%3Doz%26continue%3Dhttps%253A%252F%252Faccounts.google.com%252FManageAccount Content-Encoding gzip Transfer-Encoding chunked Date Thu,22 Dec 2011 07:31:40 GMT X-Content-Type-Options nosniff X-XSS-Protection 1; mode=block Server GSE
好了,现在我如何使用WebClient Class来包含这些标题?
我试过webClient_.Headers.Add();但效果有限,总是返回登录页面.
以下是我使用的课程.非常感谢任何帮助.
public void LoginPageRequest(Account acc) { var rparams = new RequestParams(); rparams.URL = @"https://accounts.google.com/ServiceLoginAuth?service=oz"; rparams.RequestName = "LoginPage"; rparams.Account = acc; webClient_.DownloadDataAsync(new Uri(rparams.URL),rparams); } void webClient__DownloadDataCompleted(object sender,DownloadDataCompletedEventArgs e) { RequestParams rparams = (RequestParams)e.UserState; if (rparams.RequestName == "LoginPage") { ParseLoginRequest(e.Result,e.UserState); } }
现在使用HtmlAgilityPack获取表单字段并将它们添加到Parameters集合中
public void ParseLoginRequest(byte[] data,object UserState) { RequestParams rparams = (RequestParams)UserState; rparams.ClearParams(); ASCIIEncoding encoder = new ASCIIEncoding(); string html = encoder.GetString(data); HtmlNode.ElementsFlags.Remove("form"); HtmlDocument doc = new HtmlDocument(); doc.LoadHtml(html); HtmlNode form = doc.GetElementbyId("gaia_loginform"); rparams.URL = form.GetAttributeValue("action",string.Empty); rparams.RequestName = "LoginPost"; var inputs = form.Descendants("input"); foreach (var element in inputs) { string name = element.GetAttributeValue("name","undefined"); string value = element.GetAttributeValue("value",""); if (!name.Equals("undefined")) { if (name.ToLower().Equals("email")) { value = rparams.Account.Email; } else if (name.ToLower().Equals("passwd")) { value = rparams.Account.Password; } rparams.AddParam(name,value); Console.WriteLine(name + "-" + value); } } webClient_.UploadValuesAsync(new Uri(rparams.URL),"POST",rparams.GetParams,rparams);
我究竟做错了什么?
解决方法
在一些摆弄之后,看起来WebClient类不是解决这个特定问题的最佳方法.
为了实现以下目标,我必须跳到WebRequest下面的一个级别.
在制作WebRequest(HttpWebRequest)并使用HttpWebResponse时,可以设置CookieContainer
webRequest_ = (HttpWebRequest)HttpWebRequest.Create(rparams.URL); webRequest_.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"; CookieContainer cookieJar = new CookieContainer(); webRequest_.CookieContainer = cookieJar; string html = string.Empty; try { using (WebResponse response = webRequest_.GetResponse()) { using (var streamReader = new StreamReader(response.GetResponseStream())) { html = streamReader.ReadToEnd(); ParseLoginRequest(html,response,cookieJar); } } } catch (WebException e) { using (WebResponse response = e.Response) { HttpWebResponse httpResponse = (HttpWebResponse)response; Console.WriteLine("Error code: {0}",httpResponse.StatusCode); using (var streamReader = new StreamReader(response.GetResponseStream())) Console.WriteLine(html = streamReader.ReadToEnd()); } }
然后在制作帖子时以下列方式使用相同的Cookie容器
webRequest_ = (HttpWebRequest)HttpWebRequest.Create(rparams.URL); webRequest_.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"; webRequest_.Method = "POST"; webRequest_.ContentType = "application/x-www-form-urlencoded"; webRequest_.CookieContainer = cookieJar; var parameters = new StringBuilder(); foreach (var key in rparams.Params) { parameters.AppendFormat("{0}={1}&",HttpUtility.UrlEncode(key.ToString()),HttpUtility.UrlEncode(rparams.Params[key.ToString()])); } parameters.Length -= 1; using (var writer = new StreamWriter(webRequest_.GetRequestStream())) { writer.Write(parameters.ToString()); } string html = string.Empty; using (response = webRequest_.GetResponse()) { using (var streamReader = new StreamReader(response.GetResponseStream())) { html = streamReader.ReadToEnd(); } }
所以这很有效,这段代码不适合生产使用,可以/应该进行优化.以此为例.