2010-08-01 6 views
35

Uso il controllo webbrowser per accedere a qualsiasi sito. E poi voglio scaricare qualche pagina HTML html usando WebRequest (o WebClient). Questo link deve richiedere l'autenticazione.È possibile trasferire l'autenticazione da Webbrowser a WebRequest

Come trasferire le informazioni di autenticazione di Webbrowser a Webrequest o Webclient?

+0

Dai nomi delle classi si può presumere che si stia facendo una domanda sulle classi della libreria di classi .NET di base? – Oded

+0

sì. System.Net.WebRequest – ebattulga

+0

Che tipo di autenticazione richiedono i collegamenti? Un modulo di accesso? Certificato client SSL? Autenticazione di Windows? –

risposta

1

Se è possibile recuperare i cookie necessari dal controllo WebBrowser dopo che sono stati impostati dal sito al quale si sta effettuando l'accesso, sarà necessario poter utilizzare quegli stessi cookie con WebRequest/WebClient.

This articolo descrive come utilizzare i cookie con un client Web; devi sottoclassi, ma è solo un singolo override necessario.

+0

Sto cercando di ottenere i cookie. Ma webbrowser.document.cookie è null – ebattulga

+0

@ebattulga - se il cookie è 'HttpOnly', non è possibile recuperarlo da javascript. http://msdn.microsoft.com/en-us/library/system.web.httpcookie.httponly.aspx – Giorgi

0

Non è facile realizzare ciò che si sta tentando di fare. Il server potrebbe utilizzare uno dei due tipi di autenticazione con il client (browser)

1) Autenticazione di trasporto 2) Autenticazione basata su form.

Autenticazione trasporto: in questo caso, l'autenticazione viene eseguita utilizzando la connessione di trasporto stessa; qui verranno utilizzate intestazioni HTTP personalizzate con un handshake multiway per eseguire l'autenticazione.

Autenticazione basata su moduli: questa è l'autenticazione tradizionale che viene eseguita quando si immettono le credenziali in un modulo.

In entrambi i casi, l'autenticazione potrebbe essere già avvenuta al momento dell'istanza del controllo gestito. Come qualcuno ha suggerito, puoi rubare i cookie del browser per quel dominio e usarlo con il webclient ma poi potrebbe funzionare o meno nel modo in cui ti aspetti.

Se tutto quello che vogliamo fare è scaricare qualcosa, poi vorrei vedere se ho potuto utilizzare le strutture browser per esempio, XmlHttpRequest o qualche altro meccanismo ajax scaricare ciò che si vuole come parte del DOM della pagina che ospita il controllo. Quindi puoi leggere quel contenuto dal tuo controllo, o puoi anche fare in modo che il browser inietti quel contenuto sotto il tuo controllo tramite Javascript che chiama un metodo/una proprietà sul tuo controllo.

[EDIT]

Ottieni (utilizzando plugin di Firebug in Firefox) esattamente come le forme di autenticazione basato si sta facendo nel browser. Quindi puoi scrivere codice per fare esattamente la stessa richiesta/risposta che il browser sta facendo. Al sito web, il client apparirà come qualsiasi altro client basato su browser. Quindi dovresti riuscire a scaricare tutto quello che vuoi dal sito web.

Spero che questo aiuti.

2

Un possibile modo per farlo è quello di ottenere il cookie utilizzando InternetGetCookie funzione, costruire corrispondente cookie oggetto e usarlo per il CookieContainer

Per recuperare cookie HttpOnly utilizzano InternetGetCookieEx

Ecco alcuni esempi:

InternetGetCookie() in .NET

Download using Internet Explorer Cookies

+0

Questo non ottiene tutti i cookie – ebattulga

+0

Prova InternetGetCookieEx con INTERNET_COOKIE_HTTPONLY o INTERNET_COOKIE_THIRD_PARTY –

+1

dove viene dichiarato INTERNET_COOKIE_HTTPONLY? –

0

Ho effettivamente avuto questo stesso problema sulla piattaforma Windows Mobile e l'unica cosa che ha funzionato è stato estendere il controllo WebBrowser (usando C++: <) per catturare i vars POST/GET prima che la richiesta venisse inviata.

Questa libreria può aiutarti:

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

"..il libreria implementa il pacchetto PassthroughAPP di Igor Tandetnik, che consente al cliente di intercettare tutti i HTTP e HTTPS richiesta e le risposte."

Quindi, anche se non è possibile ottenere i vars POST/GET utilizzati per l'autenticazione di base su un controllo WebBrowser standard, sarebbe possibile se si utilizza un controllo esteso come l'esempio I collegato - in effetti molti "Esteso I controlli "WebBrowser" vengono creati a causa di problemi molto simili ai tuoi. Purtroppo, per quanto ne so è necessario fare questo codice non gestito utilizzando/C++ :(.

3

Si dovrebbe essere in grado di accedere ai cookie del controllo WebBrowser con .Document.Cookie poi nel vostro HTTPWebRequest è possibile aggiungere quel biscotto al suo biscotto . contenitore
Ecco un esempio (VB.NET perché io sono più familiari lì):

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) 

E che dovrebbe trasferire il cookie dal vostro WebBrowser controllo sopra alla classe HTTPWebRequest

+0

browser.Document.Cookie è null – ebattulga

+0

Ti sei connesso e autenticato con il controllo del tuo browser Web prima di leggere il valore .Document.Cookie? – Justin

+0

WebBrowser.Document.Cookie non contiene cookie HttpOnly. –

40

Se. la domanda è solo "Come trasferire le informazioni di autenticazione di Webbrowser a Webrequest o Webclient?" questo codice è sufficiente:

È possibile chiamare il metodo GetUriCookieContainer che restituisce un CookieContainer che può essere utilizzato per la chiamata successiva con l'oggetto 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; 
} 
+0

Si noti che questo non includerà i cookie "sicuri" per impostazione predefinita. Per ottenere quelli devi solo passare in un URI che inizia con https anziché http. – AaronLS

+2

+1 per HttpOnly flag. – Jaanus

+0

In realtà, non ho idea di dove mettere o usare questo codice, potresti aiutarmi? –

1

Una risposta in ritardo per riferimenti futuri. WebBrowser utilizza la libreria UrlMon che gestisce la sessione per processo, quindi le API UrlMon come URLOpenStream o URLDownloadToFile possono essere utilizzate per scaricare qualsiasi risorsa nella stessa sessione (le API possono essere richiamate da C# tramite P/invoke). Una domanda simile ha risposto allo here.

7

Se trovato questa soluzione. Semplice creare un file Class.cs con le informazioni seguenti e chiamare la funzione statica 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(); 
    } 
} 

Esempio:

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

Questa è l'unica soluzione di lavoro per me. Parsing page con reindirizzamenti e SSO .... Grazie mille! –

+0

Ottimo! Questa è anche l'unica soluzione che ha funzionato anche per me. Salvato la mia settimana! –

1

So che questo è molto vecchia questione, ma non c'è risposta segnato quindi voglio condividere la soluzione che ho preparato

non ho trasferito i miei biscotti da browser web a WebRequest ma ho usato webclient al posto di WebRequest e per questo ci sono i passaggi qui sotto ho seguito

Creare cliente biscotto consapevoli web Parse cookie dal controllo del browser web Assegna analizzati i cookie per contenitore biscotto Crea biscotto consapevoli oggetto client Web utilizzando contenitore biscotto Usa biscotto oggetto client consapevoli web per inviare le vostre richieste ora

Spiegato in dettaglio su questo link http://www.codewithasp.net/2016/06/transferring-cookies-webbrowser-webclient-c-net.html

Problemi correlati