7

我需要以编程方式在 wordpress 管理面板中执行一些操作,但无法管理如何使用 C# 和 HttpWebRequest 登录到 Wordpress。

这是我所做的:

private void button1_Click(object sender, EventArgs e)
        {
            string url = "http://localhost/wordpress/wp-login.php";
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            CookieContainer cookies = new CookieContainer();

            SetupRequest(url, request, cookies);
            //request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
            //request.Headers["Accept-Language"] = "uk,ru;q=0.8,en-us;q=0.5,en;q=0.3";
            //request.Headers["Accept-Encoding"] = "gzip,deflate";
            //request.Headers["Accept-Charset"] = "windows-1251,utf-8;q=0.7,*;q=0.7";


            string user = "test";
            string pwd = "test";

            request.Credentials = new NetworkCredential(user, pwd);

            string data = string.Format(
                "log={0}&pwd={1}&wp-submit={2}&testcookie=1&redirect_to={3}",
                user, pwd, 
                System.Web.HttpUtility.UrlEncode("Log In"),
                System.Web.HttpUtility.UrlEncode("http://localhost/wordpress/wp-admin/"));

            SetRequestData(request, data);

            ShowResponse(request);
}

private static void SetupRequest(string url, HttpWebRequest request, CookieContainer cookies)
        {
            request.CookieContainer = cookies;
            request.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.0; uk; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 (.NET CLR 3.5.30729)";
            request.KeepAlive = true;
            request.Timeout = 120000;
            request.Method = "POST";
            request.Referer = url;
            request.ContentType = "application/x-www-form-urlencoded";
        }

        private void ShowResponse(HttpWebRequest request)
        {
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            responseTextBox.Text = (((HttpWebResponse)response).StatusDescription);
            responseTextBox.Text += "\r\n";
            StreamReader reader = new StreamReader(response.GetResponseStream());
            responseTextBox.Text += reader.ReadToEnd();
        }

        private static void SetRequestData(HttpWebRequest request, string data)
        {
            byte[] streamData = Encoding.ASCII.GetBytes(data);
            request.ContentLength = streamData.Length;

            Stream dataStream = request.GetRequestStream();
            dataStream.Write(streamData, 0, streamData.Length);
            dataStream.Close();
        }

但不幸的是,作为回应,我只得到了登录页面的 HTML 源代码,而且似乎 cookie 不包含会话 ID。我在该代码之后执行的所有请求也返回登录页面的 HTML 源,因此我可以假设它没有正确登录。

任何人都可以帮助我解决这个问题或给出工作示例吗?


我想要实现的主要目标是在 Wordpress 的 Nextgen Gallery 插件中扫描新图像。有这样做的 XML-RPC 方式吗?

提前致谢。

4

8 回答 8

11

由于 WordPress 实现了重定向,因此离开页面(重定向)会阻止 webrequest 获取正确的 cookie。

为了获得相关的 cookie,必须防止重定向。

request.AllowAutoRedirect = false;

而不是使用 cookie 容器进行登录。

请参阅以下代码:(基于 Albahari 的 C# 书中的示例)

        string loginUri = "http://www.someaddress.com/wp-login.php";
        string username = "username";
        string password = "pass";
        string reqString = "log=" + username + "&pwd=" + password;
        byte[] requestData = Encoding.UTF8.GetBytes(reqString);

        CookieContainer cc = new CookieContainer();
        var request = (HttpWebRequest)WebRequest.Create(loginUri);
        request.Proxy = null;
        request.AllowAutoRedirect = false;
        request.CookieContainer = cc;
        request.Method = "post";

        request.ContentType = "application/x-www-form-urlencoded";
        request.ContentLength = requestData.Length;
        using (Stream s = request.GetRequestStream())
            s.Write(requestData, 0, requestData.Length);

        using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
        {
            foreach (Cookie c in response.Cookies)
                Console.WriteLine(c.Name + " = " + c.Value);
        }

        string newloginUri = "http://www.someaddress.com/private/";
        HttpWebRequest newrequest = (HttpWebRequest)WebRequest.Create(newloginUri);
        newrequest.Proxy = null;
        newrequest.CookieContainer = cc;
        using (HttpWebResponse newresponse = (HttpWebResponse)newrequest.GetResponse())
        using (Stream resSteam = newresponse.GetResponseStream())
        using (StreamReader sr = new StreamReader(resSteam))
            File.WriteAllText("private.html", sr.ReadToEnd());
        System.Diagnostics.Process.Start("private.html");
于 2012-12-08T21:18:56.003 回答
4

我不知道其他人是否会觉得这有帮助,但我只是使用 WordPress API 登录。我创建了一个用户 (CRON_USR),他在晚上“登录”作为 cron 工作的一部分并执行一些任务。代码是这样的:

require(dirname(__FILE__) . '/wp-load.php' );
$user = wp_authenticate(CRON_USR, CRON_PWD);
wp_set_auth_cookie($user->ID, true, $secure_cookie); //$secure_cookie is an empty string
do_action('wp_login', CRON_USR);
wp_redirect('http://www.mysite.com/wp-admin/');
于 2010-08-03T23:31:45.957 回答
3

谢谢大家。我设法仅在使用套接字时使其工作。Wordpress 发送多个Set-Cookie标头,但HttpWebRequest仅处理此类标头的一个实例,因此丢失了一些 cookie。使用套接字时,我可以获得所有需要的 cookie 并登录到管理面板。

于 2009-08-19T13:54:34.573 回答
2
NameValueCollection loginData = new NameValueCollection();
loginData.Add("username", "your_username");
loginData.Add("password", "your_password");

WebClient client = new WebClient();
string source = Encoding.UTF8.GetString(client.UploadValues("http://www.site.com/login", loginData));

string cookie = client.ResponseHeaders["Set-Cookie"];
于 2010-03-12T11:40:09.623 回答
1

抱歉,您的代码没有明显问题。但是 Wordpress 有一个 XML-RPC 界面,必须在管理界面中启用。我为这个界面写了一些 python 脚本,它就像一个魅力。

于 2009-08-15T20:11:14.957 回答
1

我用我的 WordPress.com 帐户(受 SSL 保护)尝试了这个。我发现最简单的方法是使用 .NET 套接字获取 HTTP“Set-Cookie”标头,然后将标头解析为 .NET Cookie 对象,然后将 CookieContainer 与 HttpWebRequest 的 cookie 一起使用。

在套接字上使用 SSL 的最简单方法是在绑定到套接字的 NetworkStream 上实现 SslStream。

例子:

private void LogIn()
    {
        string fulladdress = "hostname.wordpress.com";
        string username = HttpUtility.UrlEncode("username");
        string password = HttpUtility.UrlEncode("password");

        string formdata = "log={0}&pwd={1}&redirect_to=http%3A%2F%2F{2}%2Fwp-admin%2F&testcookie=1";
        formdata = string.Format(formdata, username, password, fulladdress);
        IPHostEntry entry = Dns.GetHostEntry(fulladdress);


        Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
        s.Connect(entry.AddressList[0], 443);

        NetworkStream ns = new NetworkStream(s);

        System.Net.Security.SslStream ssl = new System.Net.Security.SslStream(ns);
        byte[] data = Encoding.UTF8.GetBytes(String.Format(WpfApplication2.Properties.Resources.LogRequest, "https://" + fulladdress, fulladdress, form.Length, username, password));

        ssl.AuthenticateAsClient(fulladdress);
        ssl.Write(data, 0, data.Length);

        StringBuilder sb = new StringBuilder();
        byte[] resp = new byte[128];
        int i = 0;
        while (ssl.Read(resp, 0, 128) > 0)
        {
            sb.Append(Encoding.UTF8.GetString(resp));
        }

        List<String> CookieHeaders = new List<string>();
        foreach (string header in sb.ToString().Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries))
        {
            if (header.StartsWith("Set-Cookie"))
            {
                CookieHeaders.Add(header.Replace("Set-Cookie: ", ""));
            }
        }

        CookieContainer jar = new CookieContainer();
        foreach (string cook in CookieHeaders)
        {
            string name, value, path, domain;
            name = value = path = domain = "";

            string[] split = cook.Split(';');
            foreach (string part in split)
            {
                if (part.StartsWith(" path="))
                {
                    path = part.Replace(" path=", "");
                }
                if (part.StartsWith(" domain="))
                {
                    domain = part.Replace(" domain=", "");
                }
                if (!part.StartsWith(" path=") && !part.StartsWith(" domain=") && part.Contains("="))
                {
                    name = part.Split('=')[0];
                    value = part.Split('=')[1];
                }
            }

            jar.Add(new Cookie(name, value, path, domain));
        }

        HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://" + fulladdress + "/wp-admin/index.php");
        req.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3";
        req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
        req.KeepAlive = false;
        req.AllowAutoRedirect = false;
        req.Referer = "https://" + fulladdress + "/wp-login.php";
        req.ContentType = "application/x-www-form-urlencoded";
        req.CookieContainer = jar;
        req.AllowAutoRedirect = true;
        req.AutomaticDecompression = DecompressionMethods.GZip;
        req.Method = "GET";
        req.Timeout = 30000;

        HttpWebResponse response = (HttpWebResponse)req.GetResponse();

        using (System.IO.StreamReader sr = new System.IO.StreamReader(response.GetResponseStream(), Encoding.UTF8))
        {
            MessageBox.Show(sr.ReadToEnd());
        }
    }

该代码效率不高,但它说明了登录到管理界面的过程。

希望能帮助到你 :)

于 2010-03-12T11:36:44.667 回答
1

TomerBu 的回答对我有用,并添加了以下内容。我必须在网站上安装 SSL 证书,添加对 TLS1.2 的支持并设置 UserAgent 才能使其正常工作。没有 TLS1.2,网络服务器立即拒绝了我的连接请求。如果没有 SSL 证书,WordPress 站点不会认为我的 C# 机器人已登录以进行后续 WebRequest(即使登录成功)。

*** 关于 TLS 的重要说明:我是安全协议新手,我只提供对我有用的东西。我安装了 .NET 4.7.2 Developer Pack 并将我的 C# 项目的目标框架更改为 .NET 4.7.2,但我仍然需要修改 ServicePointManager.SecurityProtocol,如下所示。搜索以查找最佳实践,包括更新 .NET 和在按位 ORed 语句中指定多个 TLS 版本。

// Add support for TLS 1.2 (note bitwise OR)
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

...
request.Proxy = null;
request.AllowAutoRedirect = false;
request.CookieContainer = cc;
request.Method = "post";

// Add UserAgent
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1";
于 2017-09-26T19:41:58.133 回答
0

TomerBu 为我提供了最好的答案,但缺少一些东西。

在他的代码中,替换:

 foreach (Cookie c in response.Cookies)
            Console.WriteLine(c.Name + " = " + c.Value);

经过

if (response.Cookies != null)
    {
        foreach (Cookie currentcook in response.Cookies)
             request.CookieContainer.Add(currentcook); //This is the key !!!
    }

接下来对于未来的请求,您将不得不重用 CookieContainer。

于 2013-01-28T20:13:38.253 回答