在Web浏览器控件中获取Cookies - WP7

3
为了登录到网站的某个部分,我的应用程序用户需要他们的Cookie。为此,我需要获取并将其传递到URL。
有人知道如何从浏览器控件中获取特定网站的Cookie吗?
我看到这种方法,但不是很清楚。
谢谢,TP。

请注意,当您在应用程序中使用WebBrowser控件时,它使用分隔设置,并且只能访问在使用该控件时放置在其中的Cookie。这是出于安全原因。 - Chad Moran
谢谢你的信息,查德。我确实只想访问控件本身放置的Cookie。 - turtlepower
5个回答

6
自 WP 7.1 Mango "发布"以来,如果可以这样称呼它,请参阅Windows Phone上的WebBrowser控件概述。它最近进行了一些更新,结果他们实际上已经添加了一些从WebBrowser中检索cookie的支持。在页面底部,您将找到一个微小的链接GetCookies(WebBrowser),指向一个新类的描述:WebBrowserExtensions,具有此非常方便的方法。是的,这个类只有那一个成员。我想不需要对这个扩展方法进行解释。
我并没有太多使用这种方法的经验,但是它似乎可以让你访问与JS技巧相同的内容:当前URL的cookie设置。它可能不允许设置任何东西,也不能查看其他URL的cookie。也许如果你努力使用CookieContainer,你会得到一些收获,但我怀疑。
在7.0版本中,我一直在努力实现我的应用程序的“cookie透明度”。长话短说,我的应用程序正在进行一些后台HTTP请求,并且还有一个WebBrowser来显示一些在线内容 - 如果两个连接源都向服务器发出相同的cookie,那就太好了。而且可以猜到,我的应用程序必须首先发出第一个请求,然后让浏览器导航。在这种要求下,几乎没有办法实现cookie的一致性 - 甚至使用当前最新和最辉煌的GetCookie方法,我想这也将非常困难。所以,重点是 - 可能需要使用一些隐藏的API,该API公开存在于手机上,但在SDK中被隐藏。该API可在(公共)类System.Net.Browser.WebRequestCreator中获得,可以自由使用。怪癖是:在SDK中,此类具有一个单独的公共静态属性“IWebRequestCreate ClientHttp”,其中包含一个方法“Create”,您可以使用该方法来“工厂”您的“原始http”连接 - 以防出于某种原因不想使用WebClient。在手机和模拟器上,有一个第二个公共静态属性称为“IWebRequestCreate BrowserHttp”,可以通过反射轻松返回:
PropertyInfo brwhttp = typeof(System.Net.Browser.WebRequestCreator)
    .GetProperty("BrowserHttp")

通过这个属性,您将能够获取WebBrowser内部使用的“特殊”IWebRequestCreate实例。通过使用此类打开后台HTTP请求,您将自动获得您的cookie设置,就好像它们是由WebBrowser控件创建/发送的一样,但反过来,您将无法修改HTTP标头、提供HTTP用户身份验证以及执行一些低级操作,因为所有这些设置都将与WebBrowser存储的当前“系统用户实例”同步。连接和WebBrowser之间的互操作是双向的-如果您的HTTP连接(使用“hidden property”创建)接收到任何设置/cookie等-那么WebBrowser将立即注意到它们并更新自己的缓存。在任何一方都不会有cookie/session丢失!
如果您需要在某个WebBrowser导航后被动地获取cookie以用于随后的连接,请使用GetCookie或JS方式。
但是,如果您需要先进行代码编写,然后将authz传递给WebBrowser-您可能需要深入挖掘并使用上述内容。它已被隐藏,所以请首先采用其他方法!

..不要问我是如何发现它的,或者花了多少时间:P 玩得开心

//编辑:我刚刚发现,BrowserHttp属性是访问浏览器连接工厂的正常Silverlight方式,请参见BrowserHttp。看起来它只是在为WP7平台编写的'miniSilverlight'中被隐藏了!


非常好的挖掘,可惜这个问题太老了。+1 - AnthonyWJones
非常好的发现,确实如此,向您致敬! - Art

0
// Ensure this is set to true BEFORE navigating to the page
webBrowser1.IsScriptEnabled = true;

// Once the page has loaded, you can read the cookie string
string cookieString = webBrowser1.InvokeScript("eval", new string[] { "document.cookie;" }) as string;

cookieString变量将包含文档的完整cookie。然后,您可以解析该字符串。


1
不会收集任何带有HTTPOnly属性的cookie。 - EricLaw

0

正如@quetzalcoatl已经建议的那样,您可以使用WebRequestCreator的内部实例来在浏览器实例和WebRequest实例之间共享cookie。但是,您无法直接访问cookie,我认为这只是Microsoft的安全措施。

下面的代码创建一个连接到WebBrowser实例的CookieContainer的WebReqeust对象。然后,它会发布到一个URL以登录用户并将cookie存储在容器中。完成后,应用程序实例中的所有浏览器实例都将具有所需的一组cookie。

var browser = new WebBrowser();
var brwhttp = typeof (WebRequestCreator).GetProperty("BrowserHttp");
var requestFactory = brwhttp.GetValue(browser, null) as IWebRequestCreate;
var uri = new Uri("https://www.login.com/login-handler");

var req = requestFactory.Create(uri);
req.Method = "POST";

var postParams = new Dictionary<string, string> { 
    {"username", "turtlepower"}, 
    {"password": "ZoMgPaSSw0Rd1"}
};

req.BeginGetRequestStream(aReq => {

    var webRequest = (HttpWebRequest)aReq.AsyncState;
    using (var postStream = webRequest.EndGetRequestStream(aReq)) {

        // Build your POST request here
        var postDataBuilder = new StringBuilder();
        foreach (var pair in paramsDict) {
            if (postDataBuilder.Length != 0) {
                postDataBuilder.Append("&");
            }
            postDataBuilder.AppendFormat("{0}={1}", pair.Key, HttpUtility.UrlEncode(pair.Value));
        }

        var bytes = Encoding.UTF8.GetBytes(postDataBuilder.ToString());
        postStream.Write(bytes, 0, bytes.Length);
    }

    // Receive response 
    webRequest.BeginGetResponse(aResp => {

        var webRequest2 = (HttpWebRequest) aResp.AsyncState;

        webRequest = (HttpWebRequest)aResp.AsyncState;
        string resp;

        using (var response = (HttpWebResponse)webRequest2.EndGetResponse(aResp)) {
            using (var streamResponse = response.GetResponseStream()) {
                using (var streamReader = new System.IO.StreamReader(streamResponse)) {
                    resp = streamReader.ReadToEnd();
                }
            }
        }

    }, webRequest);
}, req);

我遇到的问题之一是当服务器返回302时抛出异常 - 它似乎会抛出带有“未找到”描述的WebException错误。


0
在您提供的帖子中所描述的方法是使用WebBrowser控件的InvokeScript方法来运行一些JavaScript。然而,该帖子似乎使用了一个实际上不存在的“cookies”集合。
 string cookie = myWebBrowser.InvokeScript("document.cookie") as string;

现在是最难的部分,你得到的字符串包含页面上所有相关的cookie名称/值对,其中值仍然是Url编码的。你需要解析返回的字符串以获取所需的值。

请参阅document.cookie property文档。

编辑

重新审视一下,而不是依赖于帖子,InvokeScript在主机浏览器的窗口上调用命名函数。因此,在WebBrowser中显示的页面本身需要包括一个类似于以下内容的函数:

 function getCookie() { return document.cookie; }

那么InvokeScript看起来会像这样:

 string cookie = myWebBrowser.InvokeScript("getCookie");

你好,安东尼, 我尝试了以下代码,但是出现了 SystemException 未处理的异常。你有什么想法吗? - turtlepower
嗨,安东尼,感谢你的帮助。假设网站没有“getCookies”类型的函数,还有其他方法可以访问我的Cookie吗? - turtlepower
这将不会收集具有HTTPOnly属性的任何cookie。 - EricLaw
@EricLaw:确实,我们只能希望OP需要获取的cookie没有标记为HTTPOnly。 - AnthonyWJones

0

有一个专门为此开发的WebBrowser扩展类:

CookieCollection tempCookies = Microsoft.Phone.Controls.WebBrowserExtensions.GetCookies(this.BrowserControl);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接