Inicie sesión en el sitio web, a través de C #

81

Soy relativamente nuevo en el uso de C # y tengo una aplicación que lee partes del código fuente en un sitio web. Que todo funciona; pero el problema es que la página en cuestión requiere que el usuario inicie sesión para acceder a este código fuente. Lo que mi programa necesita es una forma de iniciar la sesión del usuario en el sitio web; una vez hecho esto, podré acceder y leer el código fuente.

El sitio web que debe iniciar sesión es: mmoinn.com/index.do?PageModule=UsersLogin

He buscado durante todo el día cómo hacer esto y he probado ejemplos, pero no he tenido suerte.

Gracias por adelantado

RyBolt
fuente
Entonces, puedo pensar en un montón de formas de hacer esto ... ¿El programa C # solicita el 'código' directamente desde el servidor a través de HTTP o usted usa la aplicación del navegador o qué? Se necesita un poco más de información.
Mitch Baker
El programa utiliza WebClient.DownloadString ("URL")

Respuestas:

112

Puede continuar usando WebClient para POST (en lugar de GET, que es el verbo HTTP que está usando actualmente con DownloadString), pero creo que le resultará más fácil trabajar con las clases WebRequest y WebResponse (ligeramente) de nivel inferior.

Hay dos partes para esto: la primera es publicar el formulario de inicio de sesión, la segunda es recuperar el encabezado "Set-cookie" y enviarlo de vuelta al servidor como "Cookie" junto con su solicitud GET. El servidor usará esta cookie para identificarlo de ahora en adelante (asumiendo que está usando autenticación basada en cookies, que estoy bastante seguro de que es porque esa página devuelve un encabezado Set-cookie que incluye "PHPSESSID").


PUBLICAR en el formulario de inicio de sesión

Las publicaciones de formulario son fáciles de simular, solo se trata de formatear los datos de la publicación de la siguiente manera:

field1=value1&field2=value2

Usando WebRequest y el código que adapté de Scott Hanselman , así es como enviaría los datos del formulario a su formulario de inicio de sesión:

string formUrl = "http://www.mmoinn.com/index.do?PageModule=UsersAction&Action=UsersLogin"; // NOTE: This is the URL the form POSTs to, not the URL of the form (you can find this in the "action" attribute of the HTML's form tag
string formParams = string.Format("email_address={0}&password={1}", "your email", "your password");
string cookieHeader;
WebRequest req = WebRequest.Create(formUrl);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
byte[] bytes = Encoding.ASCII.GetBytes(formParams);
req.ContentLength = bytes.Length;
using (Stream os = req.GetRequestStream())
{
    os.Write(bytes, 0, bytes.Length);
}
WebResponse resp = req.GetResponse();
cookieHeader = resp.Headers["Set-cookie"];

Aquí hay un ejemplo de lo que debería ver en el encabezado Set-cookie para su formulario de inicio de sesión:

PHPSESSID=c4812cffcf2c45e0357a5a93c137642e; path=/; domain=.mmoinn.com,wowmine_referer=directenter; path=/; domain=.mmoinn.com,lang=en; path=/;domain=.mmoinn.com,adt_usertype=other,adt_host=-

OBTENER la página detrás del formulario de inicio de sesión

Ahora puede realizar su solicitud GET en una página en la que debe iniciar sesión.

string pageSource;
string getUrl = "the url of the page behind the login";
WebRequest getRequest = WebRequest.Create(getUrl);
getRequest.Headers.Add("Cookie", cookieHeader);
WebResponse getResponse = getRequest.GetResponse();
using (StreamReader sr = new StreamReader(getResponse.GetResponseStream()))
{
    pageSource = sr.ReadToEnd();
}

EDITAR:

Si necesita ver los resultados del primer POST, puede recuperar el HTML que devolvió con:

using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
{
    pageSource = sr.ReadToEnd();
}

Coloque esto directamente debajo cookieHeader = resp.Headers["Set-cookie"];y luego inspeccione la cadena contenida en pageSource.

Matt Brindley
fuente
Muchas gracias por la respuesta detallada; pero todavía hay una parte de la que no estoy seguro. ¿Se supone que debo cambiar algo con respecto a "Set -cookie", "Cookie" o "PHPSESSID" que publicaste? Intenté simplemente usar ese código en un programa ingresando mi información, pero no parece que me esté registrando (supongo que estoy arruinando algo con las cookies).
El código debe estar bien para usar textualmente. El servidor establece la cookie (en Set-cookie) y el cliente (ese es usted) envía la cookie como Cookie). Lo primero que debe verificar es que el primer POST realmente lo registra, puede encontrar que el servidor esperaba otro campo en su formulario POST (por extraño que parezca, a veces necesita un campo vacío con el nombre del botón). Actualicé la publicación para mostrar cómo ver los resultados de la POST.
Matt Brindley
No estoy seguro de qué estaba haciendo mal la primera vez, ¡pero funciona ahora! Muchas gracias por la ayuda.
1
¿Cómo puedo determinar si el usuario se autenticó correctamente?
Cyral
2
Sé que se supone que no debemos dar las gracias aquí, ¡pero hombre, me salvaste el culo! +1
Owen James
39

Puede simplificar un poco las cosas creando una clase que se derive de WebClient, anulando su método GetWebRequest y estableciendo un objeto CookieContainer en él. Si siempre configura la misma instancia de CookieContainer, la administración de cookies se manejará automáticamente por usted.

Pero la única forma de acceder a HttpWebRequest antes de que se envíe es heredar de WebClient y anular ese método.

public class CookieAwareWebClient : WebClient
{
    private CookieContainer cookie = new CookieContainer();

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest request = base.GetWebRequest(address);
        if (request is HttpWebRequest)
        {
            (request as HttpWebRequest).CookieContainer = cookie;
        }
        return request;
    }
}

var client = new CookieAwareWebClient();
client.BaseAddress = @"https://www.site.com/any/base/url/";
var loginData = new NameValueCollection();
loginData.Add("login", "YourLogin");
loginData.Add("password", "YourPassword");
client.UploadValues("login.php", "POST", loginData);

//Now you are logged in and can request pages    
string htmlSource = client.DownloadString("index.php");
Josh
fuente
Al depurar, la cookie (la hizo pública) siempre está vacía. El sitio web está proporcionando cookies en las páginas que estoy descargando.
C4d
Gracias, después de varias horas de encontrar una solución, ¡esto funciona!
Essej
9

Matthew Brindley , su código funcionó muy bien para un sitio web que necesitaba (con inicio de sesión), pero necesitaba cambiar HttpWebRequesty, de lo HttpWebResponsecontrario, recibo una solicitud incorrecta 404 del servidor remoto. También me gustaría compartir mi solución usando su código, y es que lo intenté para iniciar sesión en un sitio web basado en moodle , pero no funcionó en su paso " OBTENER la página detrás del formulario de inicio de sesión " porque al publicar correctamente el inicio de sesión, el encabezado 'Set-Cookie'no devolvió nada a pesar de que lo hacen otros sitios web.

Creo que aquí es donde necesitamos almacenar cookies para las próximas solicitudes, así que agregué esto.


Al bloque de código " Enviar al formulario de inicio de sesión ":

var cookies = new CookieContainer();
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(formUrl);
req.CookieContainer = cookies;


Y al " OBTENER la página detrás del formulario de inicio de sesión ":

HttpWebRequest getRequest = (HttpWebRequest)WebRequest.Create(getUrl);
getRequest.CookieContainer = new CookieContainer();
getRequest.CookieContainer.Add(resp.Cookies);
getRequest.Headers.Add("Cookie", cookieHeader);


Al hacer esto, me permite iniciar sesión y obtener el código fuente de la "página detrás del inicio de sesión" (moodle basado en el sitio web). Sé que este es un uso vago de las CookieContainery HTTPCookies porque podemos preguntar primero si existe un conjunto de cookies previamente enviando la solicitud al servidor. De todos modos, esto funciona sin problemas, pero aquí hay una buena información para leer WebRequesty WebResponsecon proyectos de muestra y tutorial:
Recuperar contenido HTTP en .NET
Cómo usar HttpWebRequest y HttpWebResponse en .NET

Por qué tan serio
fuente
2

A veces, puede ayudar a apagar AllowAutoRedirecty configurar tanto el inicio de sesión POSTcomo las GETsolicitudes de página del mismo agente de usuario.

request.UserAgent = userAgent;
request.AllowAutoRedirect = false;
TENNESSE.
fuente