web-dev-qa-db-fra.com

Est-il possible de transférer l'authentification de Webbrowser vers WebRequest

J'utilise le contrôle du navigateur Web pour me connecter à n'importe quel site. Et puis je veux télécharger du sous-page html en utilisant WebRequest (ou WebClient). Ce lien doit nécessiter une authentification.

Comment transférer les informations d'authentification Webbrowser vers Webrequest ou Webclient?

37
ebattulga

Si la question est uniquement "Comment transférer les informations d'authentification Webbrowser vers Webrequest ou Webclient?" ce code suffit:

Vous pouvez appeler la méthode GetUriCookieContainer qui vous renvoie un CookieContainer qui peut être utilisé pour un appel ultérieur avec l'objet 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;
}
42
Alkampfer

Si trouvé cette solution. Créez simplement un fichier Class.cs avec les informations ci-dessous et appelez la fonction statique 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();
    }
}   

Échantillon:

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));
8
Roger Barreto

Vous devriez pouvoir accéder aux cookies du contrôle WebBrowser avec .Document.Cookie puis dans votre HTTPWebRequest vous pouvez ajouter ce cookie à son conteneur de cookies.
Voici un exemple (VB.NET parce que je suis le plus familier là-bas):

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)

Et cela devrait transférer le cookie de votre contrôle WebBrowser vers votre classe HTTPWebRequest.

3
Justin

Une façon possible de le faire est d'obtenir le cookie en utilisant la fonction InternetGetCookie , de construire l'objet cookie correspondant et de l'utiliser pour le CookieContainer

Pour récupérer les cookies HttpOnly, utilisez InternetGetCookieEx

Voici quelques exemples:

InternetGetCookie () dans .NET

Télécharger à l'aide de cookies Internet Explorer

2
Giorgi

Si vous pouvez récupérer les cookies nécessaires à partir du contrôle WebBrowser après qu'ils soient définis par le site auquel vous vous connectez, vous devriez pouvoir utiliser ces mêmes cookies avec WebRequest/WebClient.

This article décrit comment utiliser les cookies avec un WebClient; vous devez le sous-classer, mais ce n'est qu'un seul remplacement qui est nécessaire.

1
Bojan Rajkovic

Une réponse tardive pour de futures références. WebBrowser utilise rlMon bibliothèque qui gère la session par processus, donc les API UrlMon comme RLOpenStream ou RLDownloadToFile peuvent être utilisées pour télécharger n'importe quelle ressource sur la même session (les API peuvent être appelées depuis C # via P/invoke). Une question similaire a répondu ici .

1
noseratio

Je sais que c'est une très vieille question mais il y a une réponse marquée donc je veux partager la solution que j'ai préparée

Je n'ai pas transféré mes cookies de webbrowser vers webrequest mais j'ai utilisé webclient à la place de webrequest et pour cela il y a ci-dessous les étapes que j'ai suivies

Créer un client Web prenant en charge les cookies Analyser les cookies à partir du contrôle du navigateur Web Attribuer des cookies analysés au conteneur de cookies Créer un objet client Web prenant en charge les cookies à l'aide du conteneur de cookies Utiliser l'objet client Web prenant en charge les cookies pour envoyer vos demandes maintenant

Expliqué en détail sur ce lien http://www.codewithasp.net/2016/06/transferring-cookies-webbrowser-webclient-c-net.html

1
Nikhil Gaur

Ce n'est pas facile d'accomplir ce que vous essayez de faire. Le serveur peut utiliser l'un des deux types d'authentification avec le client (navigateur)

1) Authentification du transport 2) Authentification basée sur les formulaires.

Auth de transport: dans ce cas, l'authentification se fait à l'aide de la connexion de transport elle-même - ici, elle utilisera des en-têtes HTTP personnalisés avec une négociation multi-voies pour effectuer l'auth.

Authentification basée sur les formulaires: il s'agit de l'authentification traditionnelle qui est effectuée lorsque vous entrez vos informations d'identification dans un formulaire.

Dans les deux cas, l'authentification peut déjà avoir eu lieu au moment où votre contrôle géré est instancié. Comme quelqu'un l'a suggéré, vous pouvez voler les cookies du navigateur pour ce domaine et l'utiliser avec le client Web, mais cela peut ou non fonctionner comme vous le souhaitez.

Si tout ce que vous voulez faire est de télécharger quelque chose, je verrais si je pouvais utiliser les fonctionnalités des navigateurs pour, par exemple, XmlHttpRequest ou un autre mécanisme ajax pour télécharger ce que vous voulez dans le DOM de la page qui héberge le contrôle. Ensuite, vous pouvez lire ce contenu à partir de votre contrôle, ou vous pouvez également demander au navigateur d'injecter ce contenu dans votre contrôle via Javascript en appelant une méthode/propriété sur votre contrôle.

[ÉDITER]

Découvrez (en utilisant le plugin Firebug dans Firefox) exactement comment l'authentification basée sur les formulaires est effectuée dans le navigateur. Ensuite, vous pouvez écrire du code pour faire exactement la même demande/réponse que le navigateur fait. Pour le site Web, le client apparaîtra comme tout autre client basé sur un navigateur. Ensuite, vous devriez pouvoir télécharger tout ce que vous voulez sur le site Web.

J'espère que cela t'aides.

0
feroze

J'ai en fait rencontré ce même problème sur la plate-forme Windows Mobile, et la seule chose qui a fonctionné a été d'étendre le contrôle WebBrowser (en utilisant C++: <) pour capturer les variables POST/GET avant l'envoi de la demande.

Cette bibliothèque peut vous aider:

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

"..la bibliothèque implémente le package PassthroughAPP d'Igor Tandetnik, qui permet au client d'intercepter toutes les requêtes et réponses HTTP et HTTPS."

Donc, bien qu'il ne soit pas possible d'obtenir les variables POST/GET utilisées pour votre authentification de base sur un contrôle WebBrowser standard, il serait possible si vous utilisez un contrôle étendu tel que l'exemple que j'ai lié - en fait, de nombreux contrôles "Extended WebBrowser" sont créé à cause de problèmes très similaires aux vôtres. Malheureusement, pour autant que je sache, vous devez le faire en utilisant du code non managé/c ++ :(.

0
vdoogs