私は任意のサイトにログインするためにwebbrowserコントロールを使用しています。そして、WebRequest(またはWebClient)を使用して、いくつかのサブページのhtmlをダウンロードしたいと思います。このリンクには認証が必要です。
Webブラウザの認証情報をWebrequestまたはWebclientに転送する方法は?
質問が「Webブラウザの認証情報をWebrequestまたはWebclientに転送する方法」だけの場合このコードで十分です:
WebRequestオブジェクトでの以降の呼び出しに使用できるCookieContainerを返すGetUriCookieContainerメソッドを呼び出すことができます。
[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;
}
このソリューションが見つかった場合。以下の情報を含む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));
WebBrowser
コントロールのCookieに.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)
そしてWebBrowser
コントロールからHTTPWebRequest
クラスにCookieを転送します。
これを行う1つの可能な方法は、 InternetGetCookie 関数を使用してCookieを取得し、対応するcookie
オブジェクトを作成してCookieContainer
に使用することです
HttpOnly Cookieを取得するには InternetGetCookieEx を使用します
ここではいくつかの例を示します。
ログインしているサイトで設定された後、必要なCookieをWebBrowserコントロールから取得できる場合、WebRequest/WebClientで同じCookieを使用できるはずです。
This 記事では、WebClientでCookieを使用する方法の概要を説明しています。サブクラス化する必要がありますが、必要なのは単一のオーバーライドだけです。
将来の参考のための遅い答え。 WebBrowser
は rlMon プロセスごとにセッションを管理するライブラリを使用するため、ダウンロードには RLOpenStream または RLDownloadToFile などのUrlMon APIを使用できます同じセッション上の任意のリソース(APIはP/invokeを介してC#から呼び出すことができます)。同様の質問が回答されました ここ 。
これは非常に古い質問であることはわかっていますが、回答がマークされているので、準備したソリューションを共有したいと思います
私はcookieをwebbrowserからwebrequestに転送していませんが、webrequestの代わりにwebclientを使用しており、これには以下の手順に従います
Cookie対応のWebクライアントを作成するWebブラウザーコントロールからCookieを解析する解析済みのCookieをCookieコンテナーに割り当てるCookieコンテナーを使用してCookie対応のWebクライアントオブジェクトを作成するCookie対応のWebクライアントオブジェクトを使用して今すぐリクエストを送信する
このリンクの詳細で説明 http://www.codewithasp.net/2016/06/transferring-cookies-webbrowser-webclient-c-net.html
あなたがやろうとしていることを成し遂げることは容易ではありません。サーバーは、クライアント(ブラウザー)で2種類の認証のいずれかを使用している可能性があります
1)トランスポート認証2)フォームベースの認証。
トランスポート認証:この場合、認証はトランスポート接続自体を使用して行われます。ここでは、多方向ハンドシェイク付きのカスタムHTTPヘッダーを使用して認証を行います。
フォームベースの認証:これは、フォームに認証情報を入力するときに行われる従来の認証です。
どちらの場合も、管理対象のコントロールがインスタンス化されるまでに認証が既に行われている可能性があります。誰かがあなたがそのドメインのブラウザのクッキーを盗んでそれをウェブクライアントで使うことができると示唆したように、それからそれはあなたが期待する方法で動作するかもしれないししないかもしれません。
何かをダウンロードしたいだけの場合は、XmlHttpRequestなどのブラウザー機能を使用して、コントロールをホストしているページのDOMの一部として必要なものをダウンロードできるかどうかを確認します。次に、そのコンテンツをコントロールから読み取ることもできますし、Javascriptがコントロールのメソッド/プロパティを呼び出すことにより、ブラウザにそのコンテンツをコントロールに挿入させることもできます。
[編集]
(FirefoxのFirebugプラグインを使用して)フォームベースの認証がブラウザーでどのように行われているかを正確に調べます。次に、ブラウザが実行しているのとまったく同じ要求/応答を実行するコードを記述できます。 Webサイトでは、クライアントは他のブラウザーベースのクライアントと同じように表示されます。その後、あなたはあなたが望むものをウェブサイトからダウンロードすることができるはずです。
お役に立てれば。
私は実際にWindows Mobileプラットフォームで同じ問題を経験しましたが、機能したのはWebBrowserコントロールを(C++:<を使用して)拡張して、リクエストが送信される前にPOST/GET変数をキャプチャすることでした。
このライブラリはあなたを助けるかもしれません:
http://www.codeproject.com/KB/miscctrl/csEXWB.aspx
「..ライブラリは、Igor TandetnikによるPassthroughAPPパッケージを実装しています。これにより、クライアントはすべてのHTTPおよびHTTPS要求と応答を傍受できます。」
したがって、標準のWebBrowserコントロールで基本認証に使用されるPOST/GET変数を取得することはできませんが、リンクしたサンプルなどの拡張コントロールを使用することは可能です-実際、多くの「拡張WebBrowser」コントロールはあなたに非常に似た問題のために作成されました。残念ながら、私が知る限り、アンマネージコード/ c ++ :(。