【问题标题】:Is it possible to transfer authentication from Webbrowser to WebRequest是否可以将身份验证从 Webbrowser 转移到 WebRequest
【发布时间】:2011-03-23 21:19:08
【问题描述】:

我正在使用网络浏览器控件登录任何网站。然后我想使用 WebRequest(或 WebClient)下载一些子页面 html。此链接必须需要身份验证。

如何将 Webbrowser 身份验证信息传输到 Webrequest 或 Webclient?

【问题讨论】:

  • 从类的名称可以假设您询问的是 .NET 基类库类吗?
  • 链接需要什么样的认证?登录表格? SSL 客户端证书? Windows 身份验证?
  • 你能退后一步,描述一下你在做什么吗?可以修改网站吗?它是托管您的控件的外部网站吗?控件需要对其进行身份验证的网站提供什么?

标签: c# httpwebrequest webbrowser-control webclient


【解决方案1】:

如果问题只是“如何将 Webbrowser 身份验证信息传输到 Webrequest 或 Webclient?”这段代码就够了:

您可以调用 GetUriCookieContainer 方法,该方法返回一个 CookieContainer,可用于后续调用 WebRequest 对象。

  [DllImport("wininet.dll", SetLastError = true)]
    public static extern bool InternetGetCookieEx(
        string url, 
        string cookieName, 
        StringBuilder cookieData, 
        ref int size,
        Int32  dwFlags,
        IntPtr  lpReserved);

    private const Int32 InternetCookieHttponly = 0x2000;

/// <summary>
/// Gets the URI cookie container.
/// </summary>
/// <param name="uri">The URI.</param>
/// <returns></returns>
public static CookieContainer GetUriCookieContainer(Uri uri)
{
    CookieContainer cookies = null;
    // Determine the size of the cookie
    int datasize = 8192 * 16;
    StringBuilder cookieData = new StringBuilder(datasize);
    if (!InternetGetCookieEx(uri.ToString(), null, cookieData, ref datasize, InternetCookieHttponly, IntPtr.Zero))
    {
        if (datasize < 0)
            return null;
        // Allocate stringbuilder large enough to hold the cookie
        cookieData = new StringBuilder(datasize);
        if (!InternetGetCookieEx(
            uri.ToString(),
            null, cookieData, 
            ref datasize, 
            InternetCookieHttponly, 
            IntPtr.Zero))
            return null;
    }
    if (cookieData.Length > 0)
    {
        cookies = new CookieContainer();
        cookies.SetCookies(uri, cookieData.ToString().Replace(';', ','));
    }
    return cookies;
}

【讨论】:

  • 请注意,默认情况下这不会包括“安全”cookie。要获得这些,您只需要传入以 https 而不是 http 开头的 URI。
  • 实际上,我不知道在哪里放置或使用此代码,您能帮忙吗?
  • 您可以将此代码放在您想要的任何源代码文件中,这是一种简单的帮助方法,可以向操作系统询问您作为参数传递的特定 Uri 的所有 cookie。
【解决方案2】:

如果找到此解决方案。只需使用以下信息创建一个 Class.cs 文件并调用静态GetCookieInternal 函数。

using System;
using System.ComponentModel;
using System.Net;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Windows.Forms;


internal sealed class NativeMethods
{
    #region enums

    public enum ErrorFlags
    {
        ERROR_INSUFFICIENT_BUFFER = 122,
        ERROR_INVALID_PARAMETER = 87,
        ERROR_NO_MORE_ITEMS = 259
    }

    public enum InternetFlags
    {
        INTERNET_COOKIE_HTTPONLY = 8192, //Requires IE 8 or higher   
        INTERNET_COOKIE_THIRD_PARTY = 131072,
        INTERNET_FLAG_RESTRICTED_ZONE = 16
    }

    #endregion

    #region DLL Imports

    [SuppressUnmanagedCodeSecurity, SecurityCritical, DllImport("wininet.dll", EntryPoint = "InternetGetCookieExW", CharSet = CharSet.Unicode, SetLastError = true, ExactSpelling = true)]
    internal static extern bool InternetGetCookieEx([In] string Url, [In] string cookieName, [Out] StringBuilder cookieData, [In, Out] ref uint pchCookieData, uint flags, IntPtr reserved);

    #endregion
}


/// <SUMMARY></SUMMARY>   
/// WebBrowserCookie?   
/// webBrowser1.Document.CookieHttpOnlyCookie   
///    
public class FullWebBrowserCookie : WebBrowser
{

    [SecurityCritical]
    public static string GetCookieInternal(Uri uri, bool throwIfNoCookie)
    {
        uint pchCookieData = 0;
        string url = UriToString(uri);
        uint flag = (uint)NativeMethods.InternetFlags.INTERNET_COOKIE_HTTPONLY;

        //Gets the size of the string builder   
        if (NativeMethods.InternetGetCookieEx(url, null, null, ref pchCookieData, flag, IntPtr.Zero))
        {
            pchCookieData++;
            StringBuilder cookieData = new StringBuilder((int)pchCookieData);

            //Read the cookie   
            if (NativeMethods.InternetGetCookieEx(url, null, cookieData, ref pchCookieData, flag, IntPtr.Zero))
            {
                DemandWebPermission(uri);
                return cookieData.ToString();
            }
        }

        int lastErrorCode = Marshal.GetLastWin32Error();

        if (throwIfNoCookie || (lastErrorCode != (int)NativeMethods.ErrorFlags.ERROR_NO_MORE_ITEMS))
        {
            throw new Win32Exception(lastErrorCode);
        }

        return null;
    }

    private static void DemandWebPermission(Uri uri)
    {
        string uriString = UriToString(uri);

        if (uri.IsFile)
        {
            string localPath = uri.LocalPath;
            new FileIOPermission(FileIOPermissionAccess.Read, localPath).Demand();
        }
        else
        {
            new WebPermission(NetworkAccess.Connect, uriString).Demand();
        }
    }

    private static string UriToString(Uri uri)
    {
        if (uri == null)
        {
            throw new ArgumentNullException("uri");
        }

        UriComponents components = (uri.IsAbsoluteUri ? UriComponents.AbsoluteUri : UriComponents.SerializationInfoString);
        return new StringBuilder(uri.GetComponents(components, UriFormat.SafeUnescaped), 2083).ToString();
    }
}   

示例:

var cookies = FullWebBrowserCookie.GetCookieInternal(webBrowser1.Url, false);
WebClient wc = new WebClient();
wc.Headers.Add("Cookie: " + cookies);
wc.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
byte[] result = wc.UploadData("<URL>", "POST", System.Text.Encoding.UTF8.GetBytes(postData));

【讨论】:

  • 这对我来说是唯一可行的解​​决方案。使用重定向和 SSO 解析页面......非常感谢!
  • 太棒了!这也是唯一对我有用的解决方案。拯救了我的一周!
【解决方案3】:

您应该能够使用.Document.Cookie 访问WebBrowser 控件的cookie,然后在您的HTTPWebRequest 中您可以将该cookie 添加到其cookie 容器中。
这是一个例子(VB.NET,因为我最熟悉那里):

Dim browser As New WebBrowser()
/*Do stuff here to auth with your webbrowser and get a cookie.*/

Dim myURL As String = "http://theUrlIWant.com/"
Dim request As New HTTPWebRequest(myURL)
request.CookieContainer = New CookieContainer()
request.CookieContainer.SetCookies(myURL, browser.Document.Cookie)

这应该将 cookie 从您的 WebBrowser 控制权转移到您的 HTTPWebRequest 类。

【讨论】:

  • browser.Document.Cookie 为空
  • 在读取 .Document.Cookie 值之前,您是否已连接并通过 Web 浏览器控件进行身份验证?
  • WebBrowser.Document.Cookie 不包含 HttpOnly cookie。
  • @JasonHarrison 有没有办法获取 httponly cookie
  • @AnirudhaGupta 抱歉,我不知道如何获取 INTERNET_COOKIE_HTTPONLY
【解决方案4】:

一种可能的方法是使用InternetGetCookie函数获取cookie,构造相应的cookie对象并将其用于CookieContainer

要检索 HttpOnly cookie,请使用 InternetGetCookieEx

这里有一些例子:

InternetGetCookie() in .NET

Download using Internet Explorer Cookies

【讨论】:

  • 尝试 InternetGetCookieEx 与 INTERNET_COOKIE_HTTPONLY 或 INTERNET_COOKIE_THIRD_PARTY
  • INTERNET_COOKIE_HTTPONLY 声明在哪里?
【解决方案5】:

如果在您登录的站点设置了必要的 cookie 后,您可以从 WebBrowser 控件中检索它们,那么您应该能够将这些相同的 cookie 与 WebRequest/WebClient 一起使用。

This 文章概述了如何在 WebClient 中使用 cookie;你必须继承它,但它只需要一个覆盖。

【讨论】:

  • 我正在尝试获取 cookie。但是 webbrowser.document.cookie 是空的
  • @ebattulga - 如果 cookie 是“HttpOnly”,那么您无法从 javascript 中检索它。 msdn.microsoft.com/en-us/library/…
【解决方案6】:

供将来参考的较晚答案。 WebBrowser 使用 UrlMon 库来管理每个进程的会话,因此像 URLOpenStreamURLDownloadToFile 这样的 UrlMon API 可用于下载同一会话上的任何资源(API 可以通过 P/invoke 从 C# 调用)。 here回答了一个类似的问题。

【讨论】:

    【解决方案7】:

    我知道这是一个很老的问题,但是已经标记了答案,所以我想分享我准备的解决方案

    我没有将我的 cookie 从 webbrowser 转移到 webrequest,但我使用 webclient 代替 webrequest,为此我遵循以下步骤

    创建可识别 cookie 的 Web 客户端 从 Web 浏览器控件解析 cookie 将解析的 cookie 分配给 cookie 容器 使用 cookie 容器创建可识别 cookie 的 Web 客户端对象 立即使用 cookie 感知 Web 客户端对象发送您的请求

    在此链接http://www.codewithasp.net/2016/06/transferring-cookies-webbrowser-webclient-c-net.html有详细说明

    【讨论】:

      【解决方案8】:

      要完成你想做的事情并不容易。服务器可能正在对客户端(浏览器)使用两种类型的身份验证之一

      1) 传输认证 2) 基于表单的身份验证。

      传输身份验证:在这种情况下,身份验证是使用传输连接本身完成的 - 这里它将使用自定义 HTTP 标头和多路握手来执行身份验证。

      基于表单的身份验证:这是在您将凭据输入表单时完成的传统身份验证。

      在任何一种情况下,在您的托管控件被实例化时,身份验证可能已经发生。正如有人建议的那样,您可以窃取该域的浏览器 cookie 并将其与 webclient 一起使用,但它可能会或可能不会按您期望的方式工作。

      如果你只想下载一些东西,那么我会看看我是否可以使用浏览器工具,例如 XmlHttpRequest 或其他一些 ajax 机制来下载你想要的东西,作为托管页面的 DOM 的一部分控制。然后您可以从您的控件中读取该内容,或者您​​也可以让浏览器通过调用控件上的方法/属性的 Javascript 将该内容注入到您的控件中。

      [编辑]

      找出(在 firefox 中使用 Firebug 插件)究竟是如何在浏览器中完成基于表单的身份验证。然后,您可以编写代码来执行与浏览器完全相同的请求/响应。对于网站,客户端将与任何其他基于浏览器的客户端一样。然后你应该可以从网站上下载任何你想要的东西了。

      希望这会有所帮助。

      【讨论】:

        【解决方案9】:

        我实际上在 Windows Mobile 平台上也遇到过同样的问题,唯一有效的方法是扩展 WebBrowser 控件(使用 C++ :

        这个库可以帮助你:

        http://www.codeproject.com/KB/miscctrl/csEXWB.aspx

        "..该库实现了 Igor Tandetnik 的 PassthroughAPP 包,它使客户端能够拦截所有 HTTP 和 HTTPS 请求和响应。"

        因此,虽然不可能在标准 WebBrowser 控件上获取用于基本身份验证的 POST/GET 变量,但如果您使用扩展控件(例如我链接的示例),则有可能 - 实际上许多“扩展 WebBrowser " 控件的创建是因为与您的问题非常相似。不幸的是,据我所知,您需要使用非托管代码/c++ :(.

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-06
          • 2017-03-18
          • 2021-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多