我正在使用webbrowser控件登录任何网站。然后我想使用WebRequest(或WebClient)下载一些子页面html。此链接必须要求身份验证。
如何将Webbrowser身份验证信息传输到Webrequest或Webclient?
答案 0 :(得分:40)
如果问题只是“如何将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;
}
答案 1 :(得分:7)
如果找到这个解决方案。使用以下信息简单地创建一个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));
答案 2 :(得分:3)
您应该可以使用WebBrowser
访问.Document.Cookie
控件的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 :(得分:2)
一种可能的方法是使用InternetGetCookie函数获取cookie,构建相应的cookie
对象并将其用于CookieContainer
要检索HttpOnly Cookie,请使用InternetGetCookieEx
以下是一些例子:
答案 4 :(得分:1)
如果您可以在登录的站点设置后从WebBrowser控件中检索必要的cookie,则应该能够将这些cookie与WebRequest / WebClient一起使用。
This文章概述了如何将Cookie与WebClient一起使用;你必须将它子类化,但它只需要一个覆盖。
答案 5 :(得分:1)
未来参考的迟到答案。 WebBrowser
使用管理每个进程的会话的UrlMon库,因此可以使用URLOpenStream或URLDownloadToFile等UrlMon API下载同一会话中的任何资源(API可以通过P / invoke从C#调用)。一个类似的问题回答here。
答案 6 :(得分:1)
我知道这是一个非常古老的问题,但有答案标记,所以我想分享我准备的解决方案
我没有将我的cookies从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
答案 7 :(得分:0)
要完成你想做的事情并不容易。服务器可能正在使用客户端(浏览器)的两种身份验证之一
1)传输身份验证 2)基于表格的身份证明。
传输身份验证:在这种情况下,身份验证是使用传输连接本身完成的 - 此处它将使用带有多路握手的自定义HTTP标头来执行身份验证。
基于表单的身份验证:这是在表单中输入凭据时执行的传统身份验证。
在任何一种情况下,在实例化托管控件时可能已经发生了身份验证。正如有人建议您可以窃取该域的浏览器cookie并将其与webclient一起使用,但它可能会或可能不会按照您期望的方式工作。
如果你想要做的就是下载一些东西,那么我会看看我是否可以使用浏览器设施,例如XmlHttpRequest或其他一些ajax机制来下载你想要的东西作为托管的页面的DOM的一部分控制。然后你可以从你的控件中读取这些内容,或者你也可以让浏览器通过Javascript调用你控件上的方法/属性将这些内容注入你的控件。
[编辑]
找出(在firefox中使用Firebug插件)究竟如何在浏览器中完成基于表单的身份验证。然后,您可以编写代码来执行与浏览器完全相同的请求/响应。对于该网站,客户端将像任何其他基于浏览器的客户端一样出现。然后你应该可以从网站上下载任何你想要的东西。
希望这有帮助。
答案 8 :(得分:0)
我实际上在Windows Mobile平台上遇到过同样的问题,唯一有效的方法是在发送请求之前扩展WebBrowser控件(使用C ++:&lt;)来捕获POST / GET变量。
这个图书馆可以帮助你:
http://www.codeproject.com/KB/miscctrl/csEXWB.aspx
“..该库实现了Igor Tandetnik的PassthroughAPP包,它允许客户端拦截所有HTTP和HTTPS请求和响应。”
因此虽然不可能在标准WebBrowser控件上获得用于基本身份验证的POST / GET变量,但是如果使用扩展控件(例如我链接的示例) - 实际上很多“扩展WebBrowser”是可能的“由于与您的问题非常相似的问题而创建控件。不幸的是,据我所知,你需要使用非托管代码/ c ++ :(。