Can't login with HttpWebRequests

2019-08-15 10:39发布

问题:

i am trying to login to a forum with httpwerequests but i had no success so far, this is my code:

string url = "http://www.warriorforum.com/";

var bytes = Encoding.Default.GetBytes(@"vb_login_username=MyUsername&cookieuser=1&vb_login_password=&s=&securitytoken=guest&do=login&vb_login_md5password=d9350bad28eee253951d7c5211e50179&vb_login_md5password_utf=d9350bad28eee253951d7c5211e50179");
var container = new CookieContainer();

var request = (HttpWebRequest)(WebRequest.Create(url));
request.CookieContainer = container;
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.2 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/535.2";
request.ContentLength = bytes.Length;
request.Method = "POST";
request.KeepAlive = true;
request.AllowAutoRedirect = true;
request.AllowWriteStreamBuffering = true;
request.CookieContainer = container;
using (var requestStream = request.GetRequestStream())
    requestStream.Write(bytes, 0, bytes.Length);

var requestResponse = request.GetResponse();
using (var responsStream = requestResponse.GetResponseStream())
{
    if (responsStream != null)
    {
        using (var responseReader = new StreamReader(responsStream))
        {
            var responseStreamReader = responseReader.ReadToEnd();
            richTextBox1.Text = responseStreamReader; //this is to read the page source after the request
        }
    }
}

After the request the response is just the same page, nothing changed, no message telling me that i input wrong password or something like that.

回答1:

I just tested using my generic VBulletin login function and it seemed to work fine:

private static bool VBulletinLogin(Uri loginUrl, string user, string password)
{
    var postParams = new[] {
        new HttpParam("vb_login_username", user),
        new HttpParam("cookieuser", "1"),
        new HttpParam("vb_login_password", password),
        new HttpParam("securitytoken", "guest"),
        new HttpParam("do", "login"),
    };

    var http = new HttpContext();
    var src = http.GetEncodedPageData(loginUrl, HttpRequestType.POST, postParams);
    return src.ResponseData.Contains("Thank you for logging in");
}

Unfortunately, this uses my HttpContext class, which is part of a library I've been writing and the features are fairly intertwined. Hopefully, however, it will at least give you an idea of the post params. I've also included a few helpful structs/functions from my own class which should help. (note, requires a reference to the .NET 3.5 System.Web namespace.

First helpful struct, HttpParam:

public struct HttpParam
{
    private string _key;
    private string _value;

    public string Key { get { return HttpUtilty.UrlEncode(_key); } set { _key = value; } }
    public string Value { get { return HttpUtility.UrlEncode(_value); } set { _value = value; } }

    public HttpParam(string key, string value)
    {
        _key = key;
        _value = value;
    }

    public override string ToString()
    {
        return string.Format("{0}={1}", Key, Value);
    }
};

And a function to go along with it:

private static string GetQueryString(HttpParam[] args)
{
    return args != null
            ? string.Join("&", Array.ConvertAll(args, arg => arg.ToString()))
            : string.Empty;
}

The combination of these will help you to generate consistent, safe query strings. So in the above case:

var postParams = new[] {
    new HttpParam("vb_login_username", user),
    new HttpParam("cookieuser", "1"),
    new HttpParam("vb_login_password", password),
    new HttpParam("securitytoken", "guest"),
    new HttpParam("do", "login"),
};

var queryString = GetQueryString(postParams);

Would get you something like:

vb_login_username=<user>&cookieuser=1&vb_login_password=<password>&securitytoken=guest&do=login

Then something similar to what you already have for posting could be used, just ensure you have the correct URL. I'd also use UTF8 encoding when getting the query string bytes. For example (using your original code, slightly modified)

var postParams = new[] {
    new HttpParam("vb_login_username", "yourusername"),
    new HttpParam("cookieuser", "1"),
    new HttpParam("vb_login_password", "yourpassword"),
    new HttpParam("securitytoken", "guest"),
    new HttpParam("do", "login"),
};

string url = "http://warriorforum.com/login.php?do=login";
var container = new CookieContainer();
var buffer = Encoding.UTF8.GetBytes(GetQueryString(postParams));

var request = (HttpWebRequest)HttpWebRequest.Create(url);
request.CookieContainer = container;
request.UserAgent = "Mozilla/5.0";
request.Method = "POST";
request.KeepAlive = true;
request.AllowAutoRedirect = true;
request.CookieContainer = container;
request.ContentLength = buffer.Length;
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";

using (var requestStream = request.GetRequestStream())
    requestStream.Write(buffer, 0, buffer.Length);

using (var response = request.GetResponse())
{
    if (response.StatusCode == HttpStatusCode.OK || response.StatusCode == HttpStatusCode.NotModified)
    {
        using (var reader = new StreamReader(response.GetResponseStream()))
        {
            var result = reader.ReadToEnd();
            richTextBox1.Text = result; //this is to read the page source after the request
        }
    }
}

Note the changes with the ContentType as well.



回答2:

You seem to be missing something the browser does when you login... does that forum really need a POST or perhaps a GET ? Are all your parameters correct ? Does the web page perhaps send an additional parameter (hidden) when login happens from the browser ?

You need to see what really goes over the wire when you login manually via a browser - use Wireshark or Fiddler to find out and then simulate what happens in code...