题 是否可以将身份验证从Webbrowser转移到WebRequest


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

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


35
2017-08-01 15:09


起源


从类的名称可以假设您询问.NET基类库类? - Oded
是。 System.Net.WebRequest - ebattulga
链接需要什么样的身份验证?登录表格? SSL客户端证书? Windows身份验证? - Kieren Johnstone
表格认证。没有ssl - ebattulga
你能退后一步,描述你究竟在做什么吗?你能改变网站吗?它是一个托管您控制权的外部网站吗?控制需要从哪个网站进行身份验证? - feroze


答案:


如果问题只是“如何将Web浏览器身份验证信息传输到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;
}

40
2018-04-12 10:31



请注意,默认情况下,这不包括“安全”Cookie。要获得那些,您只需要传入以https而不是http开头的URI。 - AaronLS
+1为HttpOnly标志。 - Jaanus
实际上,我没有任何想法放置或使用此代码,你能帮忙吗? - Roger Barretto
您可以将此代码放在您想要的任何源代码文件中,这是一个简单的帮助方法,向操作系统询问您作为参数传递的特定Uri的所有cookie。 - Alkampfer


如果找到这个解决方案使用下面的信息简单地创建一个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));

7
2017-12-16 19:33



这是我唯一的解决方案。用重定向和SSO解析页面....非常感谢! - Marek Javůrek
大!这也是唯一对我有用的解决方案。节省了我的一周! - Guilherme de Jesus Santos


您应该能够访问的cookie WebBrowser 用。控制 .Document.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 类。


3
2017-08-11 13:19



browser.Document.Cookie为null - ebattulga
在阅读.Document.Cookie值之前,您是否已使用Web浏览器控件进行连接和身份验证? - Justin
WebBrowser.Document.Cookie不包含HttpOnly cookie。 - Jason Harrison
@JasonHarrison有办法获得httponly cookie - Anirudha Gupta
@AnirudhaGupta抱歉,我不知道如何获得INTERNET_COOKIE_HTTPONLY - Jason Harrison


一种可能的方法是通过使用获取cookie InternetGetCookie 功能,构建对应 cookie 对象并将其用于 CookieContainer

要检索HttpOnly cookie使用 InternetGetCookieEx

这里有些例子:

.NET中的InternetGetCookie()

使用Internet Explorer Cookie下载


2
2017-08-05 11:18



这不是所有的cookie - ebattulga
尝试使用INTERNET_COOKIE_HTTPONLY或INTERNET_COOKIE_THIRD_PARTY访问InternetGetCookieEx - Sheng Jiang 蒋晟
INTERNET_COOKIE_HTTPONLY在哪里宣布? - J. Chang


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

这个 文章概述了如何在WebClient中使用cookie;你必须将它子类化,但它只需要一个覆盖。


1
2017-08-01 15:47



我想要拿饼干。但是webbrowser.document.cookie为null - ebattulga
@ebattulga - 如果cookie是'HttpOnly',那么你无法从javascript中检索它。 msdn.microsoft.com/en-us/library/... - Giorgi


未来参考的答案很晚。 WebBrowser 使用 URLMON 管理每个进程的会话的库,所以UrlMon API就像 URLOpenStream 要么 URLDownloadToFile 可用于在同一会话中下载任何资源(可通过P / invoke从C#调用API)。一个类似的问题回答 这里


1
2017-09-27 05:42





我知道这是一个非常古老的问题,但有答案标记,所以我想分享我准备的解决方案

我没有将我的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


1
2018-06-11 12:02





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

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

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

基于表单的身份验证:这是在表单中输入凭据时执行的传统身份验证。

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

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

[编辑]

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

希望这可以帮助。


0
2017-08-03 04:28





我实际上在Windows Mobile平台上遇到过同样的问题,唯一有效的方法是在发送请求之前扩展WebBrowser控件(使用C ++:<)来捕获POST / GET变量。

这个图书馆可以帮助你:

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

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

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


0
2017-08-09 19:05