在 Web 浏览器控件中抓取 Cookie - WP7

发布于 2024-10-03 02:17:55 字数 271 浏览 0 评论 0 原文

为了登录网站的某个部分,我的应用程序的用户需要他们的 cookie。为此,我需要获取它并将其传递给 url。

有谁知道如何从浏览器控件中获取某个网站的cookie?

我看到这种方法但是不太清楚。

谢谢,TP。

In order to log into a certain part of a website the users of my application require their cookie. To do this I need to grab it and pass it to url.

Does anyone know how to grab a certain websites cookie from the browser control?

I saw this method but wasn't quite clear.

Thanks, TP.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

请你别敷衍 2024-10-10 02:17:55

自 WP 7.1 Mango“发布”起,如果有人可以称呼它,请参阅 Windows Phone 的 Web 浏览器控件概述。最近更新了一点,事实证明他们实际上添加了一些对从 WebBrowser 检索 cookie 的支持。在页面底部,您会发现一个小链接 GetCookies(WebBrowser) 指向新类的描述:WebBrowserExtensions 使用这种非常方便的方法。是的,这个班级只有一个成员。这是一种扩展方法,我想不需要对此进行解释。

我没怎么用过这个方法,但是看起来这将允许你访问与 JS 技巧相同的东西:当前 URL 的 cookieset。它可能不允许设置任何内容,也不允许查看其他 URL 的 cookie。也许如果你努力使用 CookieContainer 你会收到,但我对此表示怀疑。

在 7.0 版本中,我一直在努力为我的应用程序实现“cookie 透明度”。长话短说,我的应用程序正在执行一些后台 HTTP 请求,并且还有一个 Web 浏览器来显示一些在线内容 - 如果两个连接源都向服务器发出相同的 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 headers,userprovide http 用户身份验证,也不做一些低级的事情 - 因为所有这些设置都将与为当前“系统用户实例”存储的 WebBrowser 数据同步,如果我被允许这样调用它单用户电话设备呵呵。连接和 Web 浏览器之间的互操作双向 - 如果您的 HTTP 连接(使用“隐藏属性”创建)收到任何设置/cookies/等 - 那么 Web 浏览器将立即注意到它们并更新自己的缓存。双方都没有 cookie/会话丢失!

如果您需要在第一次 WebBrowser 导航后为您的后续连接被动获取 cookie - 请使用 GetCookie 或 JS 方式。
但是,如果您需要先编写代码,然后将 authz 传递给 WebBrowser - 您可能必须深入挖掘并使用上面的内容。它已被隐藏,因此请先使用其他方法!

..不要问我是怎么找到它或者花了多长时间:P
玩得开心

//编辑:我刚刚发现,BrowserHttp 属性是普通 Silverlight 访问浏览器连接工厂的方式,请参阅 浏览器Http。看来它只是隐藏在为WP7平台编写的“miniSilverlight”中!

As of WP 7.1 Mango "release", if one may call it, please see the WebBrowser Control Overview for Windows Phone. It has been recently updated a little bit, and it turns out that they actually have added some support for cookie-retrieval from the WebBrowser. On the bottom of the page you will find a tiny link GetCookies(WebBrowser) pointing to description of a new class: WebBrowserExtensions with this very handy method. Yes, this class has only that one single member. It's an extension method, I suppose no explanations needed on that.

I have not played with this method much, but it seems that this will allow you to access the very same thing as the JS trick: the cookieset for the current URL. It probably will not allow to set anything, nor to peek cookies for other URLs. Maybe if you play hard with the CookieContainer you will receive, but I doubt.

On the 7.0 release, I've been struggling quite hard to achieve "cookie transparency" for my App. Long story short, my app was doing some background HTTP requests, and also had a WebBrowser to show some online content -- and "it would be great" if both sources of connections would emit the same cookies to the server.. And guess what, my application had to make the first request, then let the browser navigate. With such requirements, there was virtually is no way to achieve consistency of the cookies - bah, even with the current new and glorious GetCookie method, I suppose it would be damn hard. So, to the point - it was possible, but needed to use some hidden API, that is present publicitly on the Phone, but is hidden in the SDK. The API is available the (public) class System.Net.Browser.WebRequestCreator, freely available. The quirk is: in the SDK this class has a single public static property "IWebRequestCreate ClientHttp" with a method "Create" that you can use to "factory" your "raw http" connections - in case you dont want to use the WebClient for some reason. On the phone, and on the emulator, there is a second public static property called "IWebRequestCreate BrowserHttp", easily returned by Reflection:

PropertyInfo brwhttp = typeof(System.Net.Browser.WebRequestCreator)
    .GetProperty("BrowserHttp")

with this property, you will be able to obtain a "special" internal instance of IWebRequestCreate that is used internally by the WebBrowser. By opening your background HTTP requests with this class, you will get your cookies automatically set as if they were created/sent by the WebBrowser control, but in turn - you will NOT be able to modify http headers, userprovide http user authentication and neither do a few lowlevel things - because all that settings will be synced with the WebBrowser's data stored for current 'system user instance', if I'm allowed to call it as such on the single-user Phone device heh. The interoperation between connections and the WebBrowser works both ways - if your HTTP connection (created with use of the 'hidden property') receives any settings/cookies/etc -- then the WebBrowser will instantly notice them and update its own cache. No cookie/session loss on neither of the sides!

If you need to passively get cookies for your subsequent connections after some first WebBrowser navigation - please use the GetCookie or the JS way.
But if you need your code to be first, and then pass authz to the WebBrowser -- you will probably have to dig deeper and use the above.. It's been hidden, so please resort to the other means first!

..and don't ask me how did I found it or how much time it took :P
have a nice fun with it

//edit: I've just found out, that the BrowserHttp property is a normal Silverlight's way to access the Browser's connection factory, please see BrowserHttp. It seems that it is only has been hidden in the 'miniSilverlight' written for the WP7 platform!

醉南桥 2024-10-10 02:17:55

您链接的帖子中描述的方法是使用 WebBrowser 控件的 InvokeScript 方法来运行一些 JavaScript。然而,该帖子似乎使用了实际上并不存在的“cookies”集合。

 string cookie = myWebBrowser.InvokeScript("document.cookie") as string;

现在,对于困难的部分,您获得的字符串包含页面的所有相关 cookie 名称/值对,并且这些值仍然是 Url 编码的。您需要解析返回的字符串以获取所需的值。

请参阅 document.cookie 属性文档。

编辑

重新审视它,而不是依赖帖子,InvokeScript 在主机浏览器的窗口上调用命名函数。因此,WebBrowser 中显示的页面本身需要包含如下函数:-

 function getCookie() { return document.cookie; }

那么 InvokeScript 将如下所示:-

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

The approach being described in the post you linked is to use the WebBrowser control's InvokeScript method to run some javascript. However the post appears to use a "cookies" collection which doesn't actually exist.

 string cookie = myWebBrowser.InvokeScript("document.cookie") as string;

Now for the hard part the string you get contains all pertinent cookie name/value pairs for the page with the values still being Url encoded. You will need to parse the returned string for the value you need.

See document.cookie property documentation.

Edit:

Looking at it fresh instead of relying on the post, InvokeScript invokes named function on the window of the host browser. Hence the page being displayed in the WebBrowser would itself need to include a function like:-

 function getCookie() { return document.cookie; }

Then the InvokeScript would look like:-

 string cookie = myWebBrowser.InvokeScript("getCookie");
我ぃ本無心為│何有愛 2024-10-10 02:17:55

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

下面的代码创建一个 WebReqeust 对象,连接到 WebBrowser 实例的 CookieContainer。然后它会发布到一个 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 错误。

As @quetzalcoatl already suggested, you can use internal instance of WebRequestCreator to share cookies between browser instances and instances of WebRequest. You don't get to access the cookies directly though, I think that's just a security measure by Microsoft.

This code below creates a WebReqeust object, connected to CookieContainer of WebBrowser instance. It then posts to a url to log in the user and store cookies in the container.
After it's done, all browser instances within the app instance will have required set of cookies.

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);

One of the issues I couldn't solve though was exceptions thrown when server returns 302 - it seems to throw WebException error with "Not found" description.

坐在坟头思考人生 2024-10-10 02:17:55
// 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。然后您可以解析该字符串。

// 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;

The cookieString variable will contain the full cookie for the document. You can then parse the string.

要走就滚别墨迹 2024-10-10 02:17:55

有一个 WebBrowser Extension 类正是为此开发的:

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

There is an WebBrowser Extension class which is exactly developed for this:

CookieCollection tempCookies = Microsoft.Phone.Controls.WebBrowserExtensions.GetCookies(this.BrowserControl);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文